#include #include #include #include struct canvas_buffer { unsigned int *mandelbrot_buffer; unsigned int iterations; unsigned int height; unsigned int width; double center_x; double center_y; double x_span; double y_span; }; static gboolean on_main_window_close(GtkWidget *window, gpointer data) { gtk_main_quit(); return FALSE; } static gboolean drawing_callback(GtkWidget *widget, cairo_t *cr, gpointer data) { struct canvas_buffer *buff = (struct canvas_buffer *)data; int width; int height; GtkStyleContext *style_context; int x, y; double color_scale; style_context = gtk_widget_get_style_context(widget); width = gtk_widget_get_allocated_width(widget); height = gtk_widget_get_allocated_height(widget); cairo_save(cr); /* Drawing code start */ cairo_scale(cr, 1, -1); cairo_translate(cr, (double)width/2.0, -(double)height/2.0); for (x = 0; x < buff->width; x++) { for (y = 0; y < buff->height; y++) { cairo_rectangle(cr, ((double)x - (double)(buff->width - 1) / 2), ((double)y - (double)(buff->height - 1) / 2), 1, 1); if (buff->mandelbrot_buffer[y * buff->width + x] == buff->iterations) { cairo_set_source_rgb (cr, 0, 0, 0); } else { color_scale = (double)buff->mandelbrot_buffer[y * buff->width + x] / buff->iterations; cairo_set_source_rgb (cr, (sqrt(1-color_scale)), (color_scale*color_scale), color_scale); } cairo_fill(cr); } } /* Drawing code end */ cairo_restore(cr); return FALSE; } static void calculate_mandelbrot(struct canvas_buffer *buff) { double val_per_x_pixel; double val_per_y_pixel; unsigned int i; unsigned int pixel_x; unsigned int pixel_y; double point_real, point_imag; double z_real, z_imag; double z2_real, z2_imag; if (!buff) return; /* Setup the calculation data */ val_per_x_pixel = (buff->x_span) / (buff->width - 1); val_per_y_pixel = (buff->y_span) / (buff->height - 1); for (pixel_y = 0; pixel_y < buff->height; pixel_y++) { for (pixel_x = 0; pixel_x < buff->width; pixel_x++) { point_real = (((double)pixel_x - (double)(buff->width - 1) / 2)) * val_per_x_pixel + buff->center_x; point_imag = (((double)pixel_y - (double)(buff->height - 1) / 2)) * val_per_y_pixel + buff->center_y; z_real = 0.0; z_imag = 0.0; /* Check for convergence */ for (i = 0; i < buff->iterations; i++) { z2_real = z_real * z_real - z_imag * z_imag; z2_imag = 2.0 * z_real * z_imag; z_real = z2_real + point_real; z_imag = z2_imag + point_imag; if ((z_real * z_real + z_imag * z_imag) >= 4.0) break; } buff->mandelbrot_buffer[pixel_y * buff->width + pixel_x] = i; } } } int f(void * a) { return 1; } int main(int argc, char **argv) { GtkDrawingArea *drawing_area; GtkWindow *window; GtkBuilder *builder; static struct canvas_buffer mandelbrot_buff; gtk_init(&argc, &argv); builder = gtk_builder_new_from_resource("/main.glade"); drawing_area = GTK_DRAWING_AREA(gtk_builder_get_object(builder, "drawing-area")); window = GTK_WINDOW(gtk_builder_get_object(builder, "main-window")); g_signal_connect(window, "delete-event", G_CALLBACK(on_main_window_close), NULL); g_signal_connect(G_OBJECT(drawing_area), "draw", G_CALLBACK(drawing_callback), (gpointer)&mandelbrot_buff); g_object_unref(builder); thrd_t t; thrd_create(&t, f, NULL); mandelbrot_buff.x_span = 2.8; mandelbrot_buff.y_span = 2.25; mandelbrot_buff.center_x = -0.5; mandelbrot_buff.center_y = 0.0; mandelbrot_buff.width = 1900; mandelbrot_buff.height = 1000; mandelbrot_buff.iterations = 300; mandelbrot_buff.mandelbrot_buffer = (unsigned int *)malloc(sizeof(unsigned int) * mandelbrot_buff.height * mandelbrot_buff.width); calculate_mandelbrot(&mandelbrot_buff); gtk_main(); return 0; }