159 lines
3.7 KiB
C
159 lines
3.7 KiB
C
|
#include <stdio.h>
|
||
|
#include <gtk/gtk.h>
|
||
|
#include <math.h>
|
||
|
#include <threads.h>
|
||
|
|
||
|
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;
|
||
|
}
|