#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,
#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) {
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());
}
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;
SDL_WM_SetCaption(argv[0], NULL);
- draw_mandelbrot(screen, -2.5, 1, -1, 1);
-
- yres = read(0, &xres, 1);
+ loop(&ctx);
return 0;
}