]> git.itanic.dy.fi Git - mandelbrot/blobdiff - mandelbrot.c
Fix broken aspect ratio calculation
[mandelbrot] / mandelbrot.c
index 35dc6c64b0405cd64ce4e0afa540a2201203bbf7..9ca242101ae1bad4a2f98aa5e89387dee82f36f0 100644 (file)
@@ -2,6 +2,17 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <time.h>
+#include <string.h>
+
+struct context {
+       struct SDL_Surface *screen;
+       long double origo_x, origo_y;
+       int motion_x, motion_y;         /* mouse motion */
+       int mx, my;                     /* mouse position */
+       long double zoom;
+       int scroll_enabled;
+       int zooms;
+};
 
 static void putpixel(struct SDL_Surface *screen, const int x, const int y,
                     const unsigned char r, const unsigned char g,
@@ -17,9 +28,9 @@ static void putpixel(struct SDL_Surface *screen, const int x, const int y,
 
 #define MAX_ITERATION 1000
 
-int get_mandelbrot_iterations(double x0, double y0)
+int get_mandelbrot_iterations(long double x0, long double y0)
 {
-       double x = 0, y = 0, xtemp;
+       long double x = 0, y = 0, xtemp;
        int iteration = 0;
 
        while ((x * x + y * y < 2 * 2) && iteration < MAX_ITERATION) {
@@ -34,40 +45,173 @@ int get_mandelbrot_iterations(double x0, double y0)
        return iteration;
 }
 
-int draw_mandelbrot(struct SDL_Surface *screen, double x1, double x2,
-               double y1, double y2)
+int draw_mandelbrot(struct SDL_Surface *screen, long double x1, long double x2,
+               long double y1, long double y2)
 {
-       double x0, y0, xlen, ylen, xstep, ystep;
+       long double x0, y0, xlen, ylen, xstep, ystep;
        int iteration, xs, ys;
 
        xlen = x2 - x1;
        ylen = y2 - y1;
-       xstep = xlen / (double)screen->w;
-       ystep = ylen / (double)screen->h;
-
-       for (ys = 0, y0 = y1; ys < screen->h; y0 += ystep, ys++) {
-               for (xs = 0, x0 = x1; xs < screen->w; x0 += xstep, xs++) {
+       xstep = xlen / (long double)screen->w;
+       ystep = ylen / (long double)screen->h;
+
+       y0 = y1;
+#pragma omp parallel for private(xs, ys, x0, y0)
+       for (ys = 0; ys < screen->h; ys++) {
+               y0 = y1 + ystep * ys;
+               x0 = x1;
+               for (xs = 0; xs < screen->w; xs++) {
                        iteration = get_mandelbrot_iterations(x0, y0);
 
                        if (iteration == MAX_ITERATION)
                                putpixel(screen, xs, ys, 255, 255, 255);
                        else
                                putpixel(screen, xs, ys,
-                                       iteration, 0, 0);
+                                       iteration * 8, iteration,
+                                       iteration / 4);
+                       x0 += xstep;
+               }
+       }
+
+       SDL_Flip(screen);
+       return 0;
+}
+
+#define ZOOM_FACTOR    1.5
+
+static int read_events(struct context *ctx)
+{
+       SDL_Event event;
+       int wait = 1, ret, exit = 0, delayed_exit = 0;
+
+       while (!exit) {
+               if (wait) {
+                       SDL_WaitEvent(&event);
+                       wait = 0;
+               } else {
+                       ret = SDL_PollEvent(&event);
+                       if (!ret) {
+                               wait = 1;
+                               exit = delayed_exit;
+                       }
                }
 
-               SDL_Flip(screen);
+               switch (event.type) {
+               case SDL_KEYDOWN:
+                       switch (event.key.keysym.sym) {
+                       case SDLK_ESCAPE:
+                               goto quit;
+                       default:
+                               break;
+                       }
+                       break;
+               case SDL_KEYUP:
+                       switch (event.key.keysym.sym) {
+                       default:
+                               break;
+                       }
+                       break;
+               case SDL_MOUSEBUTTONDOWN:
+                       if (event.button.button == 4) {
+                               ctx->zooms++;
+                               delayed_exit++;
+                       } else if (event.button.button == 5) {
+                               ctx->zooms--;
+                               delayed_exit++;
+                       } else {
+                               ctx->scroll_enabled = 1;
+                       }
+                       break;
+               case SDL_MOUSEBUTTONUP:
+                       ctx->scroll_enabled = 0;
+                       delayed_exit++;
+                       break;
+               case SDL_MOUSEMOTION:
+                       ctx->mx = event.motion.x;
+                       ctx->my = event.motion.y;
+                       if (!ctx->scroll_enabled)
+                               break;
+
+                       ctx->motion_x -= event.motion.xrel;
+                       ctx->motion_y -= event.motion.yrel;
+                       delayed_exit++;
+                       break;
+               case SDL_VIDEORESIZE:
+                       ctx->screen =
+                               SDL_SetVideoMode(event.resize.w,
+                                                event.resize.h,
+                                                32,
+                                                ctx->screen->flags);
+                       exit++;
+                       break;
+               case SDL_QUIT:
+                       goto quit;
+               }
        }
 
        return 0;
+quit:
+       printf("\nExiting. Good bye!\n");
+       return 1;
+}
+
+static void loop(struct context *ctx)
+{
+       long double aspect_ratio;
+       long double x1, x2, y1, y2;
+       int last_zoom;
+
+       do {
+               aspect_ratio = ctx->screen->w / (long double)ctx->screen->h;
+               ctx->origo_x += ctx->motion_x / ctx->zoom / ctx->screen->w;
+               ctx->origo_y += ctx->motion_y / ctx->zoom / ctx->screen->h;
+               ctx->motion_x = ctx->motion_y = 0;
+
+               if (ctx->zooms != last_zoom) {
+                       int dx, dy;
+
+                       dx = ctx->mx - ctx->screen->w / 2;
+                       dy = ctx->my - ctx->screen->h / 2;
+
+                       if (ctx->zooms > last_zoom) {
+                               ctx->zoom *= ZOOM_FACTOR;
+                               ctx->origo_x += dx / ctx->zoom /
+                                       (long double) ctx->screen->w;
+                               ctx->origo_y += dy / ctx->zoom /
+                                       (long double) ctx->screen->h;
+                       } else {
+                               ctx->origo_x -= dx / ctx->zoom /
+                                       (long double) ctx->screen->w;
+                               ctx->origo_y -= dy / ctx->zoom /
+                                       (long double) ctx->screen->h;
+                               ctx->zoom /= ZOOM_FACTOR;
+                       }
+
+                       last_zoom = ctx->zooms;
+               }
+
+               x1 = ctx->origo_x - aspect_ratio / ctx->zoom;
+               x2 = ctx->origo_x + aspect_ratio / ctx->zoom;
+               y1 = ctx->origo_y - 1 / ctx->zoom;
+               y2 = ctx->origo_y + 1 / ctx->zoom;
+
+               printf("Drawing area (%LF, %LF)(%LF, %LF), zoom %d\n",
+                       x1, y1, x2, y2, ctx->zooms);
+
+               draw_mandelbrot(ctx->screen, x1, x2, y1, y2);
+       } while (!read_events(ctx));
 }
 
 int main(int argc, char *argv[])
 {
-       SDL_Surface *screen;
+       struct context ctx;
        int flags = SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_RESIZABLE;
        int xres = 800, yres = 600;
 
+       memset(&ctx, 0, sizeof(ctx));
+       ctx.zoom = 1;
+
        if (SDL_Init(SDL_INIT_VIDEO) != 0) {
                fprintf(stderr, "Unable to initialize SDL: %s\n",
                        SDL_GetError());
@@ -76,8 +220,8 @@ int main(int argc, char *argv[])
        }
        atexit(SDL_Quit);
 
-       screen = SDL_SetVideoMode(xres, yres, 32, flags);
-       if (screen == NULL) {
+       ctx.screen = SDL_SetVideoMode(xres, yres, 32, flags);
+       if (ctx.screen == NULL) {
                fprintf(stderr, "Unable to set video mode: %s\n",
                        SDL_GetError());
                return 2;
@@ -85,9 +229,7 @@ int main(int argc, char *argv[])
 
        SDL_WM_SetCaption(argv[0], NULL);
 
-       draw_mandelbrot(screen, -2.5, 1, -1, 1);
-
-       yres = read(0, &xres, 1);
+       loop(&ctx);
 
        return 0;
 }