From cf4f0c83012000e5cb26326d81cce6b609d1573d Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Mon, 3 May 2010 07:44:49 +0000 Subject: [PATCH] Move gdk_pixbuf calls to main thread Hopefully this will fix some Win32 issues --- src/plugins/radar.c | 185 ++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 83 deletions(-) diff --git a/src/plugins/radar.c b/src/plugins/radar.c index ecdd22b..1bf2de2 100644 --- a/src/plugins/radar.c +++ b/src/plugins/radar.c @@ -344,11 +344,10 @@ struct _RadarConus { GtkWidget *config; time_t time; const gchar *message; - gchar *nearest; + gchar *path; GisTile *tile[2]; gpointer *tile_ref[2]; - guchar *pixels[2]; guint time_id; // "time-changed" callback ID guint refresh_id; // "refresh" callback ID @@ -367,47 +366,109 @@ void _conus_update_loading(gchar *file, goffset cur, g_free(msg); } +/* Copy images to graphics memory */ +static void _conus_update_end_copy(GisTile *tile, guchar *pixels) +{ + if (!tile->data) { + tile->data = g_new0(guint, 1); + glGenTextures(1, tile->data); + } + + guint *tex = tile->data; + glBindTexture(GL_TEXTURE_2D, *tex); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, 4, 2048, 2048, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexSubImage2D(GL_TEXTURE_2D, 0, 1,1, CONUS_WIDTH/2,CONUS_HEIGHT, + GL_RGBA, GL_UNSIGNED_BYTE, pixels); + tile->coords.n = 1.0/(CONUS_WIDTH/2); + tile->coords.w = 1.0/ CONUS_HEIGHT; + tile->coords.s = tile->coords.n + CONUS_HEIGHT / 2048.0; + tile->coords.e = tile->coords.w + (CONUS_WIDTH/2) / 2048.0; + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glFlush(); +} + +/* Split the pixbuf into east and west halves (with 2K sides) + * Also map the pixbuf's alpha values */ +static void _conus_update_end_split(guchar *pixels, guchar *west, guchar *east, + gint width, gint height, gint pxsize) +{ + g_debug("GisPluginRadar: _conus_update_thread - split"); + guchar *out[] = {west,east}; + const guchar alphamap[][4] = { + {0x04, 0xe9, 0xe7, 0x30}, + {0x01, 0x9f, 0xf4, 0x60}, + {0x03, 0x00, 0xf4, 0x90}, + }; + for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++) { + gint subx = x % (width/2); + gint idx = x / (width/2); + guchar *src = &pixels[(y*width+x)*pxsize]; + guchar *dst = &out[idx][(y*(width/2)+subx)*4]; + if (src[0] > 0xe0 && + src[1] > 0xe0 && + src[2] > 0xe0) { + dst[3] = 0x00; + } else { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = 0xff; + for (int j = 0; j < G_N_ELEMENTS(alphamap); j++) + if (src[0] == alphamap[j][0] && + src[1] == alphamap[j][1] && + src[2] == alphamap[j][2]) + dst[3] = alphamap[j][3]; + } + } +} + gboolean _conus_update_end(gpointer _conus) { RadarConus *conus = _conus; g_debug("GisPluginRadar: _conus_update_end"); - for (int i = 0; i < 2; i++) { - GisTile *tile = conus->tile[i]; - guchar *pixels = conus->pixels[i]; + /* Check error status */ + if (conus->message) { + g_warning("GisPluginRadar: _conus_update_end - %s", conus->message); + _gtk_bin_set_child(GTK_BIN(conus->config), gtk_label_new(conus->message)); + return FALSE; + } - if (!tile->data) { - tile->data = g_new0(guint, 1); - glGenTextures(1, tile->data); - } + /* Load and pixbuf */ + GError *error = NULL; + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(conus->path, &error); + guchar *pixels = gdk_pixbuf_get_pixels(pixbuf); + gint width = gdk_pixbuf_get_width(pixbuf); + gint height = gdk_pixbuf_get_height(pixbuf); + gint pxsize = gdk_pixbuf_get_has_alpha(pixbuf) ? 4 : 3; - guint *tex = tile->data; - glBindTexture(GL_TEXTURE_2D, *tex); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, 4, 2048, 2048, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexSubImage2D(GL_TEXTURE_2D, 0, 1,1, CONUS_WIDTH/2,CONUS_HEIGHT, - GL_RGBA, GL_UNSIGNED_BYTE, pixels); - tile->coords.n = 1.0/(CONUS_WIDTH/2); - tile->coords.w = 1.0/ CONUS_HEIGHT; - tile->coords.s = tile->coords.n + CONUS_HEIGHT / 2048.0; - tile->coords.e = tile->coords.w + (CONUS_WIDTH/2) / 2048.0; - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glFlush(); - - g_free(pixels); - } + /* Split pixels into east/west parts */ + guchar *pixels_west = g_malloc(4*(width/2)*height); + guchar *pixels_east = g_malloc(4*(width/2)*height); + _conus_update_end_split(pixels, pixels_west, pixels_east, + width, height, pxsize); + g_object_unref(pixbuf); - /* finish */ - _gtk_bin_set_child(GTK_BIN(conus->config), - gtk_label_new(conus->nearest)); + /* Copy pixels to graphics memory */ + _conus_update_end_copy(conus->tile[0], pixels_west); + _conus_update_end_copy(conus->tile[1], pixels_east); + g_free(pixels_west); + g_free(pixels_east); + + /* Update GUI */ + gchar *label = g_path_get_basename(conus->path); + _gtk_bin_set_child(GTK_BIN(conus->config), gtk_label_new(label)); gtk_widget_queue_draw(GTK_WIDGET(conus->viewer)); - g_free(conus->nearest); + g_free(conus->path); + g_free(label); return FALSE; } @@ -415,6 +476,7 @@ gboolean _conus_update_end(gpointer _conus) gpointer _conus_update_thread(gpointer _conus) { RadarConus *conus = _conus; + conus->message = NULL; /* Find nearest */ g_debug("GisPluginRadar: _conus_update_thread - nearest"); @@ -423,69 +485,26 @@ gpointer _conus_update_thread(gpointer _conus) GList *files = gis_http_available(conus->http, "^Conus_[^\"]*_N0Ronly.gif$", "", NULL, (offline ? NULL : conus_url)); - conus->nearest = _find_nearest(conus->time, files, 6, "%Y%m%d_%H%M"); + gchar *nearest = _find_nearest(conus->time, files, 6, "%Y%m%d_%H%M"); g_list_foreach(files, (GFunc)g_free, NULL); g_list_free(files); - if (!conus->nearest) { + if (!nearest) { conus->message = "No suitable files"; goto out; } /* Fetch the image */ g_debug("GisPluginRadar: _conus_update_thread - fetch"); - gchar *uri = g_strconcat(conus_url, conus->nearest, NULL); - gchar *path = gis_http_fetch(conus->http, uri, conus->nearest, GIS_ONCE, + gchar *uri = g_strconcat(conus_url, nearest, NULL); + conus->path = gis_http_fetch(conus->http, uri, nearest, GIS_ONCE, _conus_update_loading, conus); + g_free(nearest); g_free(uri); - if (!path) { + if (!conus->path) { conus->message = "Fetch failed"; goto out; } - /* Load and split the pixbuf into two 2K data segments */ - g_debug("GisPluginRadar: _conus_update_thread - load"); - GError *error = NULL; - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &error); - guchar *pixels = gdk_pixbuf_get_pixels(pixbuf); - gint width = gdk_pixbuf_get_width(pixbuf); - gint height = gdk_pixbuf_get_height(pixbuf); - gint pxsize = gdk_pixbuf_get_has_alpha(pixbuf) ? 4 : 3; - g_free(path); - - /* Split the pixbuf into east and west halves (with 2K sides) - * Also map the pixbuf's alpha values */ - g_debug("GisPluginRadar: _conus_update_thread - split"); - conus->pixels[0] = g_malloc(4*(width/2)*height); - conus->pixels[1] = g_malloc(4*(width/2)*height); - const guchar alphamap[][4] = { - {0x04, 0xe9, 0xe7, 0x30}, - {0x01, 0x9f, 0xf4, 0x60}, - {0x03, 0x00, 0xf4, 0x90}, - }; - for (int y = 0; y < height; y++) - for (int x = 0; x < width; x++) { - gint subx = x % (width/2); - gint idx = x / (width/2); - guchar *src = &pixels[(y*width+x)*pxsize]; - guchar *dst = &conus->pixels[idx][(y*(width/2)+subx)*4]; - if (src[0] > 0xe0 && - src[1] > 0xe0 && - src[2] > 0xe0) { - dst[3] = 0x00; - } else { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = 0xff; - for (int j = 0; j < G_N_ELEMENTS(alphamap); j++) - if (src[0] == alphamap[j][0] && - src[1] == alphamap[j][1] && - src[2] == alphamap[j][2]) - dst[3] = alphamap[j][3]; - } - } - g_object_unref(pixbuf); - out: g_debug("GisPluginRadar: _conus_update_thread - done"); g_idle_add(_conus_update_end, conus); -- 2.43.2