]> Joshua Wise's Git repositories - mandelbrot-c.git/commitdiff
initial import master
authorJoshua Wise <joshua@nyus.joshuawise.com>
Fri, 25 Jul 2008 04:39:51 +0000 (00:39 -0400)
committerJoshua Wise <joshua@nyus.joshuawise.com>
Fri, 25 Jul 2008 04:39:51 +0000 (00:39 -0400)
mandelbrot.c [new file with mode: 0644]

diff --git a/mandelbrot.c b/mandelbrot.c
new file mode 100644 (file)
index 0000000..1765630
--- /dev/null
@@ -0,0 +1,488 @@
+#include "SDL.h"
+#include <math.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <zlib.h>
+
+/* Algorithmic variables */
+int maxiters = 256;
+#define BAILOUT 2.0
+int xres = 600;
+int yres = 600;
+double xmin = -2, ymin = -2, xmax = 2, ymax = 2;
+
+/* Display variables */
+SDL_Surface* screen;
+SDL_Color palette[256],origpalette[256];
+int ppm = 0;
+int sdl = 1;
+int cycling = 0;
+
+int iterate(double x, double y)
+{
+       int i;
+       double cplxr, cplxi;
+       cplxr = y;
+       cplxi = x;
+       i = 0;
+       while ((i < maxiters) && (hypot(cplxr, cplxi) < BAILOUT))
+       {
+               double a=cplxr, b=cplxi, c=cplxr, d=cplxi;
+               i++;
+               cplxr = a*c-b*d+y;
+               cplxi = a*d+b*c+x;
+       }
+       return i;
+}
+
+void set_palette()
+{
+       if (sdl)
+               SDL_SetColors(screen, palette, 0, 256);
+}
+
+void cycle_colors()
+{
+       SDL_Color x;
+       int i;
+       x = palette[0];
+       for (i=0; i<255; i++)
+               palette[i] = palette[i+1];
+       palette[255] = x;
+       set_palette();
+}
+
+Uint32 cycle_colors_cbk(Uint32 interval)
+{
+       cycle_colors();
+       return interval;
+}
+
+void init_palette()
+{
+       int i;
+       for (i=0; i<256; i++)
+       {
+               palette[i].r = sin(((double)i)/256.0*2.0*M_PI*5.0f)*256.0;
+               palette[i].g = sin(((double)(i+64))/256.0*2.0*M_PI*4.0f)*256.0;
+               palette[i].b = sin(((double)(i+128))/256.0*2.0*M_PI*3.0f)*256.0;
+               origpalette[i] = palette[i];
+       }
+}
+
+int videoflags = SDL_SWSURFACE | SDL_RESIZABLE;
+
+void start_sdl()
+{
+       if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
+       {
+               printf("SDL init failed: %s\n", SDL_GetError());
+               exit(1);
+       }
+       atexit(SDL_Quit);
+       
+       screen = SDL_SetVideoMode(xres, yres, 8, videoflags);
+       if (!screen)
+       {
+               printf("SDL video init failed: %s\n", SDL_GetError());
+               exit(1);
+       }
+       
+       SDL_WM_SetCaption("Mandelbrot Set", "Mandelbrot");
+}
+
+double pxltofltx(int x)
+{
+       return ((double)x)*((double)(xmax-xmin))/((double)xres)+xmin;
+}
+double pxltoflty(int y)
+{
+       return ((double)y)*((double)(ymax-ymin))/((double)yres)+ymin;
+}
+
+void render()
+{
+       int x,y;
+       Uint8* buffer;
+       if (ppm)
+               printf("P6\n%d %d\n255\n", xres, yres);
+       if (sdl)
+       {
+               cycling = 0;
+               SDL_WM_SetCaption("Mandelbrot Set [working]", "Mandelbrot");
+               SDL_SetTimer(0, NULL);
+               SDL_LockSurface(screen);
+               buffer = (Uint8*)screen->pixels;
+       }
+       for (y=0;y<yres;y++)
+       {
+               for (x=0;x<xres;x++)
+               {
+                       int val = iterate(pxltofltx(x), pxltoflty(y));
+                       if (ppm)
+                               printf("%c%c%c", palette[val].r, palette[val].g, palette[val].b);
+                       if (sdl)
+                               buffer[x] = val;
+               }
+               if (sdl)
+                       buffer += screen->pitch;
+               if (!(y%10))
+               {
+                       if (sdl)
+                       {
+                               for (x=0;x<xres;x++)
+                                       buffer[x]=0;
+                               SDL_UpdateRect(screen,0,0,0,0);
+                       } else 
+                               fprintf(stderr, "%d\n", y);
+               }
+       }
+       if (sdl)
+       {
+               SDL_UpdateRect(screen, 0, 0, 0, 0);
+               SDL_UnlockSurface(screen);
+               SDL_WM_SetCaption("Mandelbrot Set", "Mandelbrot");
+       }
+}
+
+int load_palette(char* name)
+{
+       gzFile file;
+       char c[1024];
+       int idx;
+       file = gzopen(name, "rb");
+       if (file == NULL)
+       {
+               perror("gzopen");
+               return 0;
+       }
+       for (idx = 0; idx < 256; idx++)
+       {
+               char* cidx = c;
+               int accum;
+               int element;
+               gzgets(file, c, 1024);
+               
+               if ((c[0] == '\r') || (c[0] == '\n'))
+               {
+                       idx--;
+                       continue;
+               }
+               if (c[0] == 0x1A /* EOF */)
+               {
+                       gzclose(file);
+                       return 1;
+               }
+               for (element = 0; element < 3; element++)
+               {
+                       accum = 0;
+                       while (isblank(*cidx))
+                               cidx++;
+                       if (!isdigit(*cidx))
+                       {
+                               fprintf(stderr, "%s: palette file format fault on color %d -- expected digit, got `%c'\n", name, idx, *cidx);
+                               gzclose(file);
+                               return;
+                       }
+                       while (isdigit(*cidx))
+                       {
+                               accum *= 10;
+                               accum += *cidx - '0';
+                               cidx++;
+                       }
+                       switch(element)
+                       {
+                       case 0: origpalette[idx].r = palette[idx].r = accum; break;
+                       case 1: origpalette[idx].g = palette[idx].g = accum; break;
+                       case 2: origpalette[idx].b = palette[idx].b = accum; break;
+                       default: abort();
+                       }
+               }
+       }
+       gzclose(file);
+       set_palette();
+       return 1;
+}
+
+void usage(char* me)
+{
+       printf(
+               "Usage: %s [OPTION]...\n"
+               "Renders the Mandelbrot set.\n"
+               "\n"
+               "Mandatory arguments to long options are mandatory for short options too.\n"
+               "  -x, --width=PIXELS           sets the output width\n"
+               "  -y, --height=PIXELS          sets the output height\n"
+               "  -m, --maxiters=ITERATIONS    sets the maximum number of iterations\n"
+               "  -s, --sdl                    enables SDL as an output device (default)\n"
+               "  -S, --no-sdl                 disables SDL as an output device (implies -q)\n"
+               "  -p, --ppm                    enables .ppm to stdout as an output device (implies -q)\n"
+               "  -P, --no-ppm                 disables .ppm as an output device (default)\n"
+               "  -q, --quit-immediately       exits immediately after rendering\n"
+               "  -l, --location=XMIN,XMAX,YMIN,YMAX\n"
+               "                               sets the starting location\n"
+               "  -t, --palette=FILENAME       sets the palette\n"
+               "      --help                   shows this help\n"
+               "\n"
+               "Written by Joshua Wise <joshua@joshuawise.com>.\n"
+               , me
+               );
+       exit(2);
+}
+
+struct option longopts[] = {
+       {"x", required_argument, NULL, 'x'},
+       {"width", required_argument, NULL, 'x'},
+       {"y", required_argument, NULL, 'y'},
+       {"height", required_argument, NULL, 'y'},
+       {"maxiters", required_argument, NULL, 'm'},
+       {"sdl", no_argument, NULL, 's'},
+       {"ppm", no_argument, NULL, 'p'},
+       {"no-sdl", no_argument, NULL, 'S'},
+       {"no-ppm", no_argument, NULL, 'P'},
+       {"help", no_argument, NULL, 'h'},
+       {"location", required_argument, NULL, 'l'},
+       {"palette", required_argument, NULL, 't'},
+       {"quit-immediately", no_argument, NULL, 'q'},
+       {0,0,0,0}
+};
+
+int main(int argc, char** argv)
+{
+        SDL_Event event;
+        int startx, starty;
+        int buttondown = 0;
+        int dragged = 0;
+        int arg;
+        int custompalette = 0;
+        int quitimmediately = 0;
+        double yctr, ysz;
+        
+        while ((arg = getopt_long(argc, argv, "x:y:m:l:t:sSpPq", longopts, NULL)) != -1)
+        {
+               switch(arg)
+               {
+               case 'x':
+                       xres = atoi(optarg);
+                       if (!xres)
+                       {
+                               printf("%s: option `%c' requires an integer argument\n", argv[0], arg);
+                               printf("Try `%s --help' for more information.\n", argv[0]);
+                               exit(2);
+                       }
+                       break;
+               case 'y':
+                       yres = atoi(optarg);
+                       if (!yres)
+                       {
+                               printf("%s: option `%c' requires an integer argument\n", argv[0], arg);
+                               printf("Try `%s --help' for more information.\n", argv[0]);
+                               exit(2);
+                       }
+                       break;
+               case 'm':
+                       maxiters = atoi(optarg);
+                       if (!maxiters)
+                       {
+                               printf("%s: option `%c' requires an integer argument\n", argv[0], arg);
+                               printf("Try `%s --help' for more information.\n", argv[0]);
+                               exit(2);
+                       }
+                       break;
+               case 's':
+                       sdl = 1;
+                       break;
+               case 'p':
+                       ppm = 1;
+                       quitimmediately = 1;
+                       break;
+               case 'S':
+                       sdl = 0;
+                       break;
+               case 'P':
+                       ppm = 0;
+                       break;
+               case 'h':
+                       usage(argv[0]);
+                       break;
+               case 'l':
+                       {
+                       float f1,f2,f3,f4;
+                               if (sscanf(optarg, "%f,%f,%f,%f", &f1, &f2, &f3, &f4) != 4)
+                               {
+                                       printf("%s: incorrect syntax for option `%c'\n", argv[0], arg);
+                                       printf("Try %s --help' for more information.\n", argv[0]);
+                                       exit(2);
+                               }
+                               xmin = f1; xmax = f2; ymin = f3; ymax = f4;
+                       }
+                       break;
+               case 't':
+                       custompalette = load_palette(optarg);
+                       break;
+               case 'q':
+                       quitimmediately = 1;
+                       break;
+               case '?':
+               case ':':
+                       printf("Try `%s --help' for more information.\n", argv[0]);
+                       exit(2);
+                       break;
+               default:
+                       printf("Oh God I am not good with computers how did this get here?\n");
+                       exit(127);
+               }
+        }
+        
+       if (sdl)
+               start_sdl();
+       yctr = ymin + (ymax - ymin) / 2.0;
+       // get y in proportion
+       ysz = (xmax-xmin)*((double)yres)/((double)xres);
+       ymax = yctr+ysz/2; ymin = yctr-ysz/2;
+
+       if (!custompalette)
+               init_palette();
+       set_palette();
+       render();
+       if (quitimmediately)
+               exit(0);
+       while ( SDL_WaitEvent(&event) ) {
+                switch (event.type) {
+                       case SDL_KEYDOWN:
+                               if (event.key.keysym.sym == SDLK_c)
+                               {
+                                       if (!cycling)
+                                       {
+                                               SDL_WM_SetCaption("Mandelbrot Set [color cycling]", "Mandelbrot");
+                                               SDL_SetTimer(50, cycle_colors_cbk);
+                                       } else {
+                                               SDL_WM_SetCaption("Mandelbrot Set", "Mandelbrot");
+                                               SDL_SetTimer(0, NULL);
+                                       }
+                                       cycling = !cycling;
+                               } else if (event.key.keysym.sym == SDLK_r) {
+                                       int i;
+                                       for (i=0;i<256;i++)
+                                       {
+                                               palette[i].r = origpalette[i].r;
+                                               palette[i].g = origpalette[i].g;
+                                               palette[i].b = origpalette[i].b;
+                                       }
+                                       set_palette();
+                               } else if (event.key.keysym.sym == SDLK_ESCAPE ||
+                                          event.key.keysym.sym == SDLK_q) {
+                                       exit(0);
+                               } else if (event.key.keysym.sym == SDLK_p) {
+                                       ppm = 1;
+                                       render();
+                                       ppm = 0;
+                               } else if (event.key.keysym.sym == SDLK_RETURN) {
+                                       render();
+                               } else if (event.key.keysym.sym == SDLK_i) {
+                                       printf("mandelbrot by Joshua Wise\n");
+                                       printf("2005-06-19, Little Cayman\n");
+                                       printf("\n");
+                                       printf("Current settings:\n");
+                                       printf("  xmin: %f, xmax: %f\n", xmin, xmax);
+                                       printf("  ymin: %f, ymax: %f\n", ymin, ymax);
+                                       printf("  maxiters: %d, bailout: %f\n", maxiters, BAILOUT);
+                                       printf("  xres: %d, yres: %d\n", xres, yres);
+                                       printf("Recreate with:\n");
+                                       printf("  %s -x%d -y%d -l%f,%f,%f,%f -m%d\n", argv[0], xres,yres,xmin,xmax,ymin,ymax,maxiters);
+                               }
+                               break;
+                       case SDL_MOUSEBUTTONDOWN:
+                               if (event.button.button == 1)
+                                       buttondown = 1;
+                               startx = event.button.x;
+                               starty = event.button.y;
+                               break;
+                       case SDL_MOUSEMOTION:
+                               if (buttondown)
+                                       dragged = 1;
+                               break;
+                       case SDL_MOUSEBUTTONUP:
+                               if (event.button.button == 1)
+                                       buttondown = 0;
+                               if (!dragged)
+                               {
+                                       if (event.button.button == 1 || event.button.button == 3)
+                                       {
+                                               double xsz = xmax-xmin, ysz = ymax-ymin;
+                                               double x,y;
+                                               double scalar;
+                                               if (event.button.button == 1)
+                                                       scalar = 1.0/2.0;
+                                               else
+                                                       scalar = 2.0/1.0;
+                                               xsz *= scalar;
+                                               ysz *= scalar;
+                                               x = pxltofltx(event.button.x);
+                                               y = pxltoflty(event.button.y);
+                                               xmax = x + xsz / 2;
+                                               xmin = x - xsz / 2;
+                                               ymax = y + ysz / 2;
+                                               ymin = y - ysz / 2;
+                                               render();
+                                       } else if (event.button.button == 2) {
+                                               xmax = ymax = 2;
+                                               xmin = ymin = -2;
+                                               render();
+                                       }
+                                       dragged = 0;
+                                       break;
+                               } else {
+                                       double newmaxx, newminx, newmaxy, newminy;
+                                       if (event.button.x > startx)
+                                       {
+                                               newmaxx = pxltofltx(event.button.x);
+                                               newminx = pxltofltx(startx);
+                                       } else {
+                                               newminx = pxltofltx(event.button.x);
+                                               newmaxx = pxltofltx(startx);
+                                       }
+                                       if (event.button.y > starty)
+                                       {
+                                               newmaxy = pxltoflty(event.button.y);
+                                               newminy = pxltoflty(starty);
+                                       } else {
+                                               newminy = pxltoflty(event.button.y);
+                                               newmaxy = pxltoflty(starty);
+                                       }
+                                       yctr = newminy + (newmaxy - newminy) / 2.0;
+                                       // get y in proportion
+                                       ysz = (newmaxx-newminx)*((double)yres)/((double)xres);
+                                       ymax = yctr+ysz/2; ymin = yctr-ysz/2;
+                                       xmax = newmaxx; xmin = newminx;
+                                       render();
+                                       dragged = 0;
+                                       break;
+                               }
+                       case SDL_VIDEORESIZE:
+                       {
+                               screen = SDL_SetVideoMode(event.resize.w, event.resize.h,
+                                                         screen->format->BitsPerPixel,
+                                                         videoflags);
+                               if (!screen)
+                               {
+                                       fprintf(stderr, "Couldn't resize screen\n");
+                                       exit(1);
+                               }
+                               SDL_SetColors(screen, palette, 0, 256);
+                               xres = event.resize.w;
+                               yres = event.resize.h;
+                               yctr = ymin + (ymax - ymin) / 2.0;
+                               // get y in proportion
+                               ysz = (xmax-xmin)*((double)yres)/((double)xres);
+                               ymax = yctr+ysz/2; ymin = yctr-ysz/2;
+                               render();
+                               break;
+                       }
+                       case SDL_QUIT:
+                               return;
+               }
+       }
+       return 1;
+}
This page took 0.037015 seconds and 4 git commands to generate.