#include #include #include #include #include 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, const unsigned char b) { int offset = y * screen->pitch + x * 4; unsigned char *buf = screen->pixels; buf[offset++] = b; buf[offset++] = g; buf[offset] = r; } #define MAX_ITERATION 1000 int get_mandelbrot_iterations(long double x0, long double y0) { long double x = 0, y = 0, xtemp; int iteration = 0; while ((x * x + y * y < 2 * 2) && iteration < MAX_ITERATION) { xtemp = x * x - y * y + x0; y = 2 * x * y + y0; x = xtemp; iteration++; } return iteration; } int draw_mandelbrot(struct SDL_Surface *screen, long double x1, long double x2, long double y1, long double y2) { long double x0, y0, xlen, ylen, xstep, ystep; int iteration, xs, ys; xlen = x2 - x1; ylen = y2 - y1; 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 * 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; } } 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[]) { 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()); return 1; } atexit(SDL_Quit); 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; } SDL_WM_SetCaption(argv[0], NULL); loop(&ctx); return 0; }