gliv-1.6
[gliv.git] / src / loading.c
blob50f91589c1ae68a212ce37ad6730f349cce7478b
1 /*
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 ************************************/
25 #include "gliv.h"
27 #include <stdio.h> /* FILE, fopen(), fread(), fclose(), perror() */
28 #include <signal.h> /* signal(), SIG_DFL, SIGSEGV */
29 #include <string.h> /* strlen(), strrchr() */
30 #include <GL/gl.h>
32 extern rt_struct *rt;
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)
44 gint level;
45 texture_map *map;
47 if (im != NULL) {
48 for (level = 0; level < im->nb_maps; level++) {
49 map = im->maps + level;
51 glDeleteTextures(map->nb_tiles, map->tex_ids);
52 g_free(map->tex_ids);
54 glDeleteLists(map->list, map->nb_tiles);
55 g_free(map->tiles);
58 g_free(im->maps);
59 g_free(im->ident);
60 g_free(im);
64 static void segv_handler(gint sig)
66 const gchar *sig_str;
68 sig_str = g_strsignal(sig);
70 if (loading_filename == NULL)
71 ERROR_MSG(_("%s not while loading an image\n"), sig_str);
72 else
73 ERROR_MSG(_("%s while loading %s\n"), sig_str, loading_filename);
75 imagemagick_finish();
77 signal(sig, SIG_DFL);
78 raise(sig);
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)
89 gchar *alpha_str;
91 g_free(im->ident);
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;
102 gchar *tmp, *ext;
104 ext = strrchr(filename, '.');
105 if (ext == NULL) {
106 ERROR_MSG(_("%s: unknown extension\n"), filename);
107 return LOADER_NONE;
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')
115 *tmp += 'a' - 'A';
117 res = ext_to_loader(ext, strlen(ext));
119 g_free(ext);
121 if (res == NULL) {
122 ERROR_MSG(_("%s: unknown extension\n"), filename);
123 return LOADER_NONE;
126 return res->loader;
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)
135 gchar *pixel, *end;
137 process_events();
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)
144 if (pixel[3] == 0)
146 * alpha == 0
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);
160 #ifdef GTK2
161 #define UNREF_LOADER(loader) g_object_unref(loader)
162 #else
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)
166 #endif
168 GdkPixbuf *load_gdk_pixbuf(const gchar * filename)
170 guchar buf[4096];
171 gsize size;
172 FILE *file;
173 GdkPixbufLoader *loader;
174 GdkPixbuf *pixbuf;
176 #ifdef GTK2
177 GError *err = NULL;
178 #endif
180 file = fopen(filename, "r");
181 if (file == NULL) {
182 perror(filename);
183 return NULL;
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) {
190 #ifdef GTK2
191 g_printerr("%s: %s\n", locale_to_utf8(filename), err->message);
192 g_error_free(err);
193 err = NULL;
194 #endif
195 break;
198 process_events();
201 gdk_pixbuf_loader_close(loader, &err);
202 #ifdef GTK2
203 if (err != NULL) {
204 g_printerr("%s: %s\n", locale_to_utf8(filename), err->message);
205 g_error_free(err);
207 #endif
209 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
210 if (pixbuf != NULL)
211 gdk_pixbuf_ref(pixbuf);
213 fclose(file);
214 UNREF_LOADER(loader);
215 return pixbuf;
218 static GdkPixbuf *file_to_pixbuf(const gchar * filename)
220 loader_t loader;
221 GdkPixbuf *pixbuf;
223 loader = loader_by_filename(filename);
225 switch (loader) {
226 case LOADER_PIXBUF:
227 pixbuf = load_gdk_pixbuf(filename);
228 break;
230 case LOADER_MAGICK:
231 pixbuf = load_with_imagemagick(filename);
232 break;
234 /* case LOADER_NONE: */
235 default:
236 pixbuf = NULL;
239 if (pixbuf == NULL && options->force) {
240 pixbuf = load_gdk_pixbuf(filename);
241 if (pixbuf == NULL)
242 pixbuf = load_with_imagemagick(filename);
245 if (pixbuf == NULL)
246 ERROR_MSG(_("Cannot load %s\n"), filename);
248 return pixbuf;
251 G_GNUC_PURE static gint nb_maps(gint dim)
253 gint ret = 1;
255 while (dim > rt->max_texture_size) {
256 dim *= MIPMAP_RATIO;
257 ret++;
260 return ret;
263 gliv_image *load_file(const gchar * filename)
265 gliv_image *im;
266 GdkPixbuf *loaded_image;
268 set_loading(filename);
270 process_events();
272 loaded_image = file_to_pixbuf(filename);
273 if (loaded_image == NULL) {
274 /* Loading failed. */
275 set_loading(NULL);
276 return NULL;
279 im = g_new(gliv_image, 1);
280 im->ident = NULL;
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);
286 if (options->mipmap)
287 im->nb_maps = MIN(nb_maps(im->width), nb_maps(im->height));
288 else
289 im->nb_maps = 1;
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;
295 if (im->has_alpha)
296 clean_alpha(loaded_image);
298 create_maps(im);
300 /* If there is a segfault it won't be because of the loading. */
301 set_loading(NULL);
303 return im;