Reorganize functions in code
This commit is contained in:
parent
4b150c8097
commit
ea699e5c48
1 changed files with 212 additions and 183 deletions
385
visor.c
385
visor.c
|
@ -12,6 +12,12 @@
|
||||||
#define MAX_THREADS 32
|
#define MAX_THREADS 32
|
||||||
#define STR(x) #x
|
#define STR(x) #x
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******* Program data structures *******/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int32_t thread_count;
|
int32_t thread_count;
|
||||||
|
|
||||||
struct threadInfo {
|
struct threadInfo {
|
||||||
|
@ -50,63 +56,31 @@ struct planeView {
|
||||||
// struct planeView mandelbrot = { 0.00000000001, 0, 0, 0.001643721971153, 0.822467633298876};
|
// struct planeView mandelbrot = { 0.00000000001, 0, 0, 0.001643721971153, 0.822467633298876};
|
||||||
struct planeView mandelbrot = { 1, 0, 0, 0, 0};
|
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] = {
|
struct threadInfo *info = arg;
|
||||||
{ 66, 30, 15 },
|
int32_t index = info->index;
|
||||||
{ 25, 7, 26 },
|
while (true) {
|
||||||
{ 9, 1, 47 },
|
pthread_mutex_lock(&pixmapMutex);
|
||||||
{ 4, 4, 73 },
|
while (!pixmapAvailable || info->complete) {
|
||||||
{ 0, 7, 100 },
|
pthread_cond_wait(&pixmapCond, &pixmapMutex);
|
||||||
{ 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;
|
|
||||||
}
|
}
|
||||||
}
|
pthread_mutex_unlock(&pixmapMutex);
|
||||||
|
info->drawing = true;
|
||||||
void color_from_iteration(int *r, int *g, int *b, double x0, double y0)
|
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);
|
|
||||||
|
|
||||||
#undef MAX_ITERATION
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_mandelbrot(struct threadInfo *info)
|
void draw_mandelbrot(struct threadInfo *info)
|
||||||
|
@ -150,143 +124,77 @@ void draw_mandelbrot(struct threadInfo *info)
|
||||||
info->complete = true;
|
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;
|
double x = 0;
|
||||||
int32_t index = info->index;
|
double y = 0;
|
||||||
while (true) {
|
int iteration = 0;
|
||||||
pthread_mutex_lock(&pixmapMutex);
|
while (x*x + y*y <= ESC_RAD*ESC_RAD && iteration < MAX_ITERATION) {
|
||||||
while(!pixmapAvailable || info->complete) {
|
double xtmp = xtmp = x*x - y*y + x0;
|
||||||
pthread_cond_wait(&pixmapCond, &pixmapMutex);
|
y = 2*x*y + y0;
|
||||||
}
|
x = xtmp;
|
||||||
pthread_mutex_unlock(&pixmapMutex);
|
iteration++;
|
||||||
info->drawing = true;
|
|
||||||
draw_mandelbrot(info);
|
|
||||||
info->drawing = false;
|
|
||||||
}
|
}
|
||||||
|
// 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 create_surface(GtkWidget *widget)
|
void color_lookup(int *r, int *g, int *b, double mu)
|
||||||
{
|
{
|
||||||
cairo_t *cr;
|
static const int table16[16][3] = {
|
||||||
|
{ 66, 30, 15 },
|
||||||
pthread_mutex_lock(&pixmapMutex);
|
{ 25, 7, 26 },
|
||||||
pixmapAvailable = false; // Mark drawing area as unavailable
|
{ 9, 1, 47 },
|
||||||
pthread_mutex_unlock(&pixmapMutex);
|
{ 4, 4, 73 },
|
||||||
|
{ 0, 7, 100 },
|
||||||
bool allWritersStopped;
|
{ 12, 44, 138 },
|
||||||
do { // Wait until all writing threads have been stopped
|
{ 24, 82, 177 },
|
||||||
allWritersStopped = true;
|
{ 57, 125, 209 },
|
||||||
for (int32_t i = 0; i < thread_count; i++) {
|
{ 134, 181, 229 },
|
||||||
if (threads[i].drawing) {
|
{ 211, 236, 248 },
|
||||||
allWritersStopped = false;
|
{ 241, 233, 191 },
|
||||||
}
|
{ 248, 201, 95 },
|
||||||
}
|
{ 255, 170, 0 },
|
||||||
} while (!allWritersStopped);
|
{ 204, 128, 0 },
|
||||||
for (int32_t i = 0; i < thread_count; i++) {
|
{ 153, 87, 0 },
|
||||||
threads[i].complete = false;
|
{ 106, 52, 3 }
|
||||||
}
|
};
|
||||||
|
// *r = 0; // (1000.0-i)/1000.0*256.0;
|
||||||
if (surface) {
|
// *g = 0; // (1000.0-i)/1000.0*256.0;
|
||||||
cairo_surface_destroy(surface);
|
// *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];
|
||||||
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
|
*g = table16[mod][1];
|
||||||
gtk_widget_get_width(widget),
|
*b = table16[mod][2];
|
||||||
gtk_widget_get_height(widget));
|
if (mu == 0 || mu >= MAX_ITERATION - 50) {
|
||||||
|
*r = *g = *b = 0;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void plane_resize(GtkWidget *widget)
|
|
||||||
{
|
|
||||||
if (!surface) {
|
|
||||||
create_surface(widget);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef MAX_ITERATION
|
||||||
|
|
||||||
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));
|
/******* Main thread code *******/
|
||||||
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);
|
void print_usage(FILE *stream);
|
||||||
|
static void app_activate(GApplication *app);
|
||||||
|
|
||||||
da = g_object_new(GTK_TYPE_DRAWING_AREA,
|
void draw_plane(GtkDrawingArea *da, cairo_t *cr, int width, int height, gpointer data);
|
||||||
"accessible-role", GTK_ACCESSIBLE_ROLE_IMG,
|
void plane_resize(GtkWidget *widget);
|
||||||
NULL);
|
void create_surface(GtkWidget *widget);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
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);
|
stat = g_application_run(G_APPLICATION(app), argc, argv);
|
||||||
g_object_unref(app);
|
g_object_unref(app);
|
||||||
|
|
||||||
// TODO: cancel all other threads here
|
|
||||||
return stat;
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue