From ea699e5c4878b57077ee08094b9c3f90ab16126a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20Kapri=C5=A1?= Date: Tue, 7 Oct 2025 21:31:19 +0100 Subject: [PATCH] Reorganize functions in code --- visor.c | 395 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 212 insertions(+), 183 deletions(-) diff --git a/visor.c b/visor.c index 647e825..19d5645 100644 --- a/visor.c +++ b/visor.c @@ -12,6 +12,12 @@ #define MAX_THREADS 32 #define STR(x) #x + + +/******* Program data structures *******/ + + + int32_t thread_count; struct threadInfo { @@ -50,65 +56,33 @@ struct planeView { // struct planeView mandelbrot = { 0.00000000001, 0, 0, 0.001643721971153, 0.822467633298876}; struct planeView mandelbrot = { 1, 0, 0, 0, 0}; -#define MAX_ITERATION 1000 -#define ESC_RAD 20.0 -void color_lookup(int *r, int *g, int *b, double mu) + + +/******* Worker thread code *******/ + + + +void draw_mandelbrot(struct threadInfo *info); + +void color_from_iteration(int *r, int *g, int *b, double x0, double y0); +void color_lookup(int *r, int *g, int *b, double mu); + +void *writer_thread(void *arg) { - static const int table16[16][3] = { - { 66, 30, 15 }, - { 25, 7, 26 }, - { 9, 1, 47 }, - { 4, 4, 73 }, - { 0, 7, 100 }, - { 12, 44, 138 }, - { 24, 82, 177 }, - { 57, 125, 209 }, - { 134, 181, 229 }, - { 211, 236, 248 }, - { 241, 233, 191 }, - { 248, 201, 95 }, - { 255, 170, 0 }, - { 204, 128, 0 }, - { 153, 87, 0 }, - { 106, 52, 3 } - }; - // *r = 0; // (1000.0-i)/1000.0*256.0; - // *g = 0; // (1000.0-i)/1000.0*256.0; - // *b = ((double) MAX_ITERATION - i - 1) / MAX_ITERATION * 255.0 - log(log(2)) / log(2); // (i/MAX_ITERATION) - int mod = (int) mu % 16; - *r = table16[mod][0]; - *g = table16[mod][1]; - *b = table16[mod][2]; - if (mu == 0 || mu >= MAX_ITERATION - 50) { - *r = *g = *b = 0; + struct threadInfo *info = arg; + int32_t index = info->index; + while (true) { + pthread_mutex_lock(&pixmapMutex); + while (!pixmapAvailable || info->complete) { + pthread_cond_wait(&pixmapCond, &pixmapMutex); + } + pthread_mutex_unlock(&pixmapMutex); + info->drawing = true; + draw_mandelbrot(info); + info->drawing = false; } } -void color_from_iteration(int *r, int *g, int *b, double x0, double y0) -{ - double x = 0; - double y = 0; - int iteration = 0; - while (x*x + y*y <= ESC_RAD*ESC_RAD && iteration < MAX_ITERATION) { - double xtmp = xtmp = x*x - y*y + x0; - y = 2*x*y + y0; - x = xtmp; - iteration++; - } - // at this point iteration is the number of iterations required for the value to - // escape. X and Y contain the first escaped value - - double mu = (iteration + 1 - log(log(sqrt(x*x+y*y)))/log(2)); - if (mu < 0) - mu = 0; - if (mu > MAX_ITERATION) - mu = MAX_ITERATION; - - color_lookup(r, g, b, mu); - -#undef MAX_ITERATION -} - void draw_mandelbrot(struct threadInfo *info) { int h = mandelbrot.height; @@ -150,143 +124,77 @@ void draw_mandelbrot(struct threadInfo *info) info->complete = true; } -void *writer_thread(void *arg) +#define MAX_ITERATION 1000 +#define ESC_RAD 20.0 +void color_from_iteration(int *r, int *g, int *b, double x0, double y0) { - struct threadInfo *info = arg; - int32_t index = info->index; - while (true) { - pthread_mutex_lock(&pixmapMutex); - while(!pixmapAvailable || info->complete) { - pthread_cond_wait(&pixmapCond, &pixmapMutex); - } - pthread_mutex_unlock(&pixmapMutex); - info->drawing = true; - draw_mandelbrot(info); - info->drawing = false; + double x = 0; + double y = 0; + int iteration = 0; + while (x*x + y*y <= ESC_RAD*ESC_RAD && iteration < MAX_ITERATION) { + double xtmp = xtmp = x*x - y*y + x0; + y = 2*x*y + y0; + x = xtmp; + iteration++; + } + // at this point iteration is the number of iterations required for the value to + // escape. X and Y contain the first escaped value + + double mu = (iteration + 1 - log(log(sqrt(x*x+y*y)))/log(2)); + if (mu < 0) + mu = 0; + if (mu > MAX_ITERATION) + mu = MAX_ITERATION; + + color_lookup(r, g, b, mu); + +} + +void color_lookup(int *r, int *g, int *b, double mu) +{ + static const int table16[16][3] = { + { 66, 30, 15 }, + { 25, 7, 26 }, + { 9, 1, 47 }, + { 4, 4, 73 }, + { 0, 7, 100 }, + { 12, 44, 138 }, + { 24, 82, 177 }, + { 57, 125, 209 }, + { 134, 181, 229 }, + { 211, 236, 248 }, + { 241, 233, 191 }, + { 248, 201, 95 }, + { 255, 170, 0 }, + { 204, 128, 0 }, + { 153, 87, 0 }, + { 106, 52, 3 } + }; + // *r = 0; // (1000.0-i)/1000.0*256.0; + // *g = 0; // (1000.0-i)/1000.0*256.0; + // *b = ((double) MAX_ITERATION - i - 1) / MAX_ITERATION * 255.0 - log(log(2)) / log(2); // (i/MAX_ITERATION) + int mod = (int) mu % 16; + *r = table16[mod][0]; + *g = table16[mod][1]; + *b = table16[mod][2]; + if (mu == 0 || mu >= MAX_ITERATION - 50) { + *r = *g = *b = 0; } } +#undef MAX_ITERATION -void create_surface(GtkWidget *widget) -{ - cairo_t *cr; - pthread_mutex_lock(&pixmapMutex); - pixmapAvailable = false; // Mark drawing area as unavailable - pthread_mutex_unlock(&pixmapMutex); - bool allWritersStopped; - do { // Wait until all writing threads have been stopped - allWritersStopped = true; - for (int32_t i = 0; i < thread_count; i++) { - if (threads[i].drawing) { - allWritersStopped = false; - } - } - } while (!allWritersStopped); - for (int32_t i = 0; i < thread_count; i++) { - threads[i].complete = false; - } +/******* Main thread code *******/ - if (surface) { - cairo_surface_destroy(surface); - } - surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, - gtk_widget_get_width(widget), - gtk_widget_get_height(widget)); - cr = cairo_create(surface); +void print_usage(FILE *stream); +static void app_activate(GApplication *app); - cairo_surface_flush(surface); - int h = cairo_image_surface_get_height(surface); - int w = cairo_image_surface_get_width(surface); - mandelbrot.height = h; - mandelbrot.width = w; - pixmap = cairo_image_surface_get_data(surface); - cairo_surface_mark_dirty(surface); - - pthread_mutex_lock(&pixmapMutex); - pixmapAvailable = true; - pthread_mutex_unlock(&pixmapMutex); - pthread_cond_broadcast(&pixmapCond); - - cairo_destroy(cr); -} - -void plane_resize(GtkWidget *widget) -{ - if (!surface) { - create_surface(widget); - } -} - -void draw_plane(GtkDrawingArea *da, cairo_t *cr, int width, int height, gpointer data) -{ - cairo_set_source_surface(cr, surface, 0, 0); - cairo_paint(cr); -} - -static void app_activate(GApplication *app) -{ - GtkWidget *win; - GtkWidget *btn1; - GtkWidget *btn2; - GtkWidget *bigBox; - GtkWidget *vertBox; - GtkDrawingArea *da; - - win = gtk_application_window_new(GTK_APPLICATION(app)); - gtk_window_set_title(GTK_WINDOW(win), "Mandelbrot visualiser"); - gtk_window_set_default_size(GTK_WINDOW(win), 800, 600); - - btn1 = gtk_button_new_with_label("A"); - gtk_widget_set_size_request(GTK_WIDGET(btn1), 20, 20); - gtk_widget_set_margin_bottom(GTK_WIDGET(btn1), 5); - gtk_widget_set_margin_top(GTK_WIDGET(btn1), 5); - gtk_widget_set_margin_start(GTK_WIDGET(btn1), 5); - gtk_widget_set_margin_end(GTK_WIDGET(btn1), 5); - btn2 = gtk_button_new_with_label("B"); - gtk_widget_set_size_request(GTK_WIDGET(btn2), 20, 20); - gtk_widget_set_margin_bottom(GTK_WIDGET(btn2), 5); - gtk_widget_set_margin_top(GTK_WIDGET(btn2), 5); - gtk_widget_set_margin_start(GTK_WIDGET(btn2), 5); - gtk_widget_set_margin_end(GTK_WIDGET(btn2), 5); - - vertBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); - gtk_widget_set_valign(GTK_WIDGET(vertBox), GTK_ALIGN_START); - gtk_box_append(GTK_BOX(vertBox), btn1); - gtk_box_append(GTK_BOX(vertBox), btn2); - - bigBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - da = g_object_new(GTK_TYPE_DRAWING_AREA, - "accessible-role", GTK_ACCESSIBLE_ROLE_IMG, - NULL); - gtk_widget_set_hexpand(GTK_WIDGET(da), true); - gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(da), 300); - gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(da), 200); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(da), draw_plane, NULL, NULL); - g_signal_connect(da, "resize", G_CALLBACK(plane_resize), NULL); - - // TODO: implement later drag = gtk_gesture_drag_new(); - - gtk_box_append(GTK_BOX(bigBox), GTK_WIDGET(da)); - gtk_box_append(GTK_BOX(bigBox), vertBox); - gtk_window_set_child(GTK_WINDOW(win), bigBox); - - gtk_window_present(GTK_WINDOW(win)); -} - -void print_usage(FILE *stream) -{ - char *err_msg = "Mandelbrot visualiser (visor):\n" - "Usage:\n" - "visor -h : Show this help\n" - "visor [threads] : Run the GTK visualizer with a given number\n" - " of threads (default " STR(DEFAULT_THREADS) ")\n" - " [1.." STR(MAX_THREADS) "]\n"; - fprintf(stream, "%s", err_msg); -} +void draw_plane(GtkDrawingArea *da, cairo_t *cr, int width, int height, gpointer data); +void plane_resize(GtkWidget *widget); +void create_surface(GtkWidget *widget); int main(int argc, char **argv) { @@ -352,6 +260,127 @@ int main(int argc, char **argv) stat = g_application_run(G_APPLICATION(app), argc, argv); g_object_unref(app); - // TODO: cancel all other threads here return stat; } + +void print_usage(FILE *stream) +{ + char *err_msg = "Mandelbrot visualiser (visor):\n" + "Usage:\n" + "visor -h : Show this help\n" + "visor [threads] : Run the GTK visualizer with a given number\n" + " of threads (default " STR(DEFAULT_THREADS) ")\n" + " [1.." STR(MAX_THREADS) "]\n"; + fprintf(stream, "%s", err_msg); +} + +static void app_activate(GApplication *app) +{ + GtkWidget *win; + GtkWidget *btn1; + GtkWidget *btn2; + GtkWidget *bigBox; + GtkWidget *vertBox; + GtkDrawingArea *da; + + win = gtk_application_window_new(GTK_APPLICATION(app)); + gtk_window_set_title(GTK_WINDOW(win), "Mandelbrot visualiser"); + gtk_window_set_default_size(GTK_WINDOW(win), 800, 600); + + btn1 = gtk_button_new_with_label("A"); + gtk_widget_set_size_request(GTK_WIDGET(btn1), 20, 20); + gtk_widget_set_margin_bottom(GTK_WIDGET(btn1), 5); + gtk_widget_set_margin_top(GTK_WIDGET(btn1), 5); + gtk_widget_set_margin_start(GTK_WIDGET(btn1), 5); + gtk_widget_set_margin_end(GTK_WIDGET(btn1), 5); + btn2 = gtk_button_new_with_label("B"); + gtk_widget_set_size_request(GTK_WIDGET(btn2), 20, 20); + gtk_widget_set_margin_bottom(GTK_WIDGET(btn2), 5); + gtk_widget_set_margin_top(GTK_WIDGET(btn2), 5); + gtk_widget_set_margin_start(GTK_WIDGET(btn2), 5); + gtk_widget_set_margin_end(GTK_WIDGET(btn2), 5); + + vertBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_widget_set_valign(GTK_WIDGET(vertBox), GTK_ALIGN_START); + gtk_box_append(GTK_BOX(vertBox), btn1); + gtk_box_append(GTK_BOX(vertBox), btn2); + + bigBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + + da = g_object_new(GTK_TYPE_DRAWING_AREA, + "accessible-role", GTK_ACCESSIBLE_ROLE_IMG, + NULL); + gtk_widget_set_hexpand(GTK_WIDGET(da), true); + gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(da), 300); + gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(da), 200); + gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(da), draw_plane, NULL, NULL); + g_signal_connect(da, "resize", G_CALLBACK(plane_resize), NULL); + + // TODO: implement later drag = gtk_gesture_drag_new(); + + gtk_box_append(GTK_BOX(bigBox), GTK_WIDGET(da)); + gtk_box_append(GTK_BOX(bigBox), vertBox); + gtk_window_set_child(GTK_WINDOW(win), bigBox); + + gtk_window_present(GTK_WINDOW(win)); +} + +void draw_plane(GtkDrawingArea *da, cairo_t *cr, int width, int height, gpointer data) +{ + cairo_set_source_surface(cr, surface, 0, 0); + cairo_paint(cr); +} + +void plane_resize(GtkWidget *widget) +{ + if (!surface) { + create_surface(widget); + } +} + +void create_surface(GtkWidget *widget) +{ + cairo_t *cr; + + pthread_mutex_lock(&pixmapMutex); + pixmapAvailable = false; // Mark drawing area as unavailable + pthread_mutex_unlock(&pixmapMutex); + + bool allWritersStopped; + do { // Wait until all writing threads have been stopped + allWritersStopped = true; + for (int32_t i = 0; i < thread_count; i++) { + if (threads[i].drawing) { + allWritersStopped = false; + } + } + } while (!allWritersStopped); + for (int32_t i = 0; i < thread_count; i++) { + threads[i].complete = false; + } + + if (surface) { + cairo_surface_destroy(surface); + } + + surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, + gtk_widget_get_width(widget), + gtk_widget_get_height(widget)); + + cr = cairo_create(surface); + + cairo_surface_flush(surface); + int h = cairo_image_surface_get_height(surface); + int w = cairo_image_surface_get_width(surface); + mandelbrot.height = h; + mandelbrot.width = w; + pixmap = cairo_image_surface_get_data(surface); + cairo_surface_mark_dirty(surface); + + pthread_mutex_lock(&pixmapMutex); + pixmapAvailable = true; + pthread_mutex_unlock(&pixmapMutex); + pthread_cond_broadcast(&pixmapCond); + + cairo_destroy(cr); +}