2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <gfc@altern.org>
21 /************************************
22 * Loading and unloading of images. *
23 ************************************/
27 #include <stdio.h> /* FILE, fopen(), fread(), fclose(), perror() */
28 #include <signal.h> /* signal(), SIG_DFL, SIGSEGV */
29 #include <string.h> /* strlen(), strrchr() */
33 extern options_struct
*options
;
35 static const gchar
*loading_filename
= NULL
;
37 gboolean
is_loading(void)
39 return loading_filename
!= NULL
;
42 void destroy_image(gliv_image
* im
)
48 for (level
= 0; level
< im
->nb_maps
; level
++) {
49 map
= im
->maps
+ level
;
51 glDeleteTextures(map
->nb_tiles
, map
->tex_ids
);
54 glDeleteLists(map
->list
, map
->nb_tiles
);
64 static void segv_handler(gint sig
)
68 sig_str
= g_strsignal(sig
);
70 if (loading_filename
== NULL
)
71 ERROR_MSG(_("%s not while loading an image\n"), sig_str
);
73 ERROR_MSG(_("%s while loading %s\n"), sig_str
, loading_filename
);
81 /* Called when the first image is loaded. */
82 void install_segv_handler(void)
84 signal(SIGSEGV
, segv_handler
);
87 void fill_ident(gliv_image
* im
)
93 alpha_str
= im
->has_alpha
? _("alpha channel") : _("no alpha channel");
95 im
->ident
= g_strdup_printf("%s (%u/%u) (%s)", (gchar
*) im
->node
->data
,
96 im
->number
+ 1, get_list_length(), alpha_str
);
99 loader_t
loader_by_filename(const gchar
* filename
)
101 const struct format
*res
;
104 ext
= strrchr(filename
, '.');
106 ERROR_MSG(_("%s: unknown extension\n"), filename
);
110 ext
= g_strdup(ext
+ 1);
112 /* Downcase the extension so that we can do case sensitive strcmp. */
113 for (tmp
= ext
; *tmp
!= '\0'; tmp
++)
114 if (*tmp
>= 'A' && *tmp
<= 'Z')
117 res
= ext_to_loader(ext
, strlen(ext
));
122 ERROR_MSG(_("%s: unknown extension\n"), filename
);
130 * Blacken image pixels with alpha == 0.
131 * These pixels are invisible but may alter the bilinear filtering.
133 static void clean_alpha(GdkPixbuf
* pixbuf
)
139 pixel
= gdk_pixbuf_get_pixels(pixbuf
);
140 end
= pixel
+ gdk_pixbuf_get_rowstride(pixbuf
) *
141 gdk_pixbuf_get_height(pixbuf
);
143 for (; pixel
!= end
; pixel
+= 4)
147 * This is not valid C since a cast cannot be a lvalue but...
149 *((guint32
*) pixel
) = 0;
152 static void set_loading(const gchar
* filename
)
154 /* Used if there is a segfault. */
155 loading_filename
= filename
;
157 set_loading_entry(filename
);
161 #define UNREF_LOADER(loader) g_object_unref(loader)
163 #define UNREF_LOADER(loader) gtk_object_unref(GTK_OBJECT(loader))
164 #define gdk_pixbuf_loader_close(loader, err) gdk_pixbuf_loader_close(loader)
165 #define gdk_pixbuf_loader_write(l, b, s, e) gdk_pixbuf_loader_write(l, b, s)
168 GdkPixbuf
*load_gdk_pixbuf(const gchar
* filename
)
173 GdkPixbufLoader
*loader
;
180 file
= fopen(filename
, "r");
186 loader
= gdk_pixbuf_loader_new();
188 while ((size
= fread(buf
, 1, sizeof(buf
), file
)) > 0) {
189 if (gdk_pixbuf_loader_write(loader
, buf
, size
, &err
) == FALSE
) {
191 g_printerr("%s: %s\n", locale_to_utf8(filename
), err
->message
);
201 gdk_pixbuf_loader_close(loader
, &err
);
204 g_printerr("%s: %s\n", locale_to_utf8(filename
), err
->message
);
209 pixbuf
= gdk_pixbuf_loader_get_pixbuf(loader
);
211 gdk_pixbuf_ref(pixbuf
);
214 UNREF_LOADER(loader
);
218 static GdkPixbuf
*file_to_pixbuf(const gchar
* filename
)
223 loader
= loader_by_filename(filename
);
227 pixbuf
= load_gdk_pixbuf(filename
);
231 pixbuf
= load_with_imagemagick(filename
);
234 /* case LOADER_NONE: */
239 if (pixbuf
== NULL
&& options
->force
) {
240 pixbuf
= load_gdk_pixbuf(filename
);
242 pixbuf
= load_with_imagemagick(filename
);
246 ERROR_MSG(_("Cannot load %s\n"), filename
);
251 G_GNUC_PURE
static gint
nb_maps(gint dim
)
255 while (dim
> rt
->max_texture_size
) {
263 gliv_image
*load_file(const gchar
* filename
)
266 GdkPixbuf
*loaded_image
;
268 set_loading(filename
);
272 loaded_image
= file_to_pixbuf(filename
);
273 if (loaded_image
== NULL
) {
274 /* Loading failed. */
279 im
= g_new(gliv_image
, 1);
282 im
->width
= gdk_pixbuf_get_width(loaded_image
);
283 im
->height
= gdk_pixbuf_get_height(loaded_image
);
284 im
->has_alpha
= gdk_pixbuf_get_has_alpha(loaded_image
);
287 im
->nb_maps
= MIN(nb_maps(im
->width
), nb_maps(im
->height
));
291 im
->maps
= g_new(texture_map
, im
->nb_maps
);
292 im
->maps
[0].map_init
= g_new(loading_data
, 1);
293 im
->maps
[0].map_init
->pixbuf
= loaded_image
;
296 clean_alpha(loaded_image
);
300 /* If there is a segfault it won't be because of the loading. */