Merged older cs.po file with newest pot file.
[gliv/czech_localization.git] / src / loading.c
blob6d3cad4cb721561f3676f083d8d2615963b57135
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 <guichaz@yahoo.fr>
21 /***********************************
22 * Loading and unloading of images *
23 ***********************************/
25 #include <stdio.h> /* FILE, fopen(), fread(), fclose(), perror() */
26 #include <signal.h> /* signal(), SIG_DFL, SIGSEGV */
27 #include <string.h> /* strlen(), strrchr() */
29 #include "gliv.h"
30 #include "loading.h"
31 #include "options.h"
32 #include "gliv-image.h"
33 #include "messages.h"
34 #include "str_utils.h"
35 #include "formats.h"
36 #include "params.h"
37 #include "files_list.h"
38 #include "textures.h"
39 #include "thread.h"
40 #include "decompression.h"
41 #include "thumbnails.h"
42 #include "rendering.h"
43 #include "tree_browser.h"
45 extern rt_struct *rt;
46 extern options_struct *options;
47 extern GlivImage *current_image;
49 /* Used to know at any time if we are loading an image. */
50 static gchar *loading_filename = NULL;
53 * Used to be quiet when we try to load files
54 * not explicitly requested by the user.
56 static gint quiet = 0;
58 void start_quiet(void)
60 quiet++;
63 void stop_quiet(void)
65 quiet--;
68 const gchar *currently_loading(void)
70 return loading_filename;
73 static void segv_handler(gint sig)
75 const gchar *sig_str;
77 signal(sig, SIG_DFL);
78 sig_str = g_strsignal(sig);
80 if (loading_filename == NULL)
81 g_printerr(_("%s not while loading an image\n"), sig_str);
82 else
83 g_printerr(_("%s while loading %s\n"), sig_str, loading_filename);
85 raise(sig);
88 /* Called when the first image is loaded. */
89 void install_segv_handler(void)
91 signal(SIGSEGV, segv_handler);
94 void fill_ident(GlivImage * im)
96 gchar *alpha_str = NULL;
97 gint im_nr;
99 g_free(im->ident);
101 if (im->has_alpha)
102 alpha_str = g_strconcat(" (", _("alpha channel"), ")", NULL);
103 else
104 alpha_str = g_strdup("");
106 im_nr = get_image_number(im);
107 im->ident = g_strdup_printf("%s (%u/%u)%s",
108 im->node ?
109 filename_to_utf8(im->node->data) : "",
110 im_nr + 1, get_list_length(), alpha_str);
112 g_free(alpha_str);
115 const gchar *get_extension(const gchar * filename)
117 const gchar *ext;
118 const gchar *basename;
120 basename = strrchr(filename, '/');
121 if (basename == NULL)
122 basename = filename;
123 else
124 basename++;
126 ext = strrchr(basename, '.');
127 if (ext != NULL)
128 /* Skip the '.' */
129 ext++;
131 return ext;
134 #define LOADING_ERROR if (!quiet) g_printerr
136 static loader_t get_decompressor(const gchar * filename, gint ext_len)
138 const struct format *res;
140 /* We want the image extension between image_ext_start and image_ext_end. */
141 const gchar *image_ext_end = filename + strlen(filename) - ext_len - 1;
142 const gchar *image_ext_start = image_ext_end - 1;
144 gint image_ext_length = 0;
145 gchar *image_ext;
147 while (image_ext_start > filename && *image_ext_start != '.') {
148 image_ext_length++;
149 image_ext_start--;
152 image_ext = g_strndup(image_ext_start + 1, image_ext_length);
153 res = ext_to_loader(image_ext, image_ext_length);
155 g_free(image_ext);
157 if (res == NULL) {
158 LOADING_ERROR(_("%s: unknown decompressed extension\n"),
159 filename_to_utf8(filename));
160 return LOADER_NONE;
163 switch (res->loader) {
164 case LOADER_DECOMP:
165 LOADING_ERROR(_("%s: image cannot be compressed twice\n"),
166 filename_to_utf8(filename));
167 return LOADER_NONE;
169 case LOADER_PIXBUF:
170 return LOADER_DECOMP_PIXBUF;
172 case LOADER_DOT_GLIV:
173 return LOADER_DECOMP_DOT_GLIV;
175 default:
176 return LOADER_NONE;
180 loader_t get_loader(const gchar * filename)
182 const struct format *res;
183 const gchar *ext;
184 gint ext_len;
186 ext = get_extension(filename);
187 if (ext == NULL) {
188 LOADING_ERROR(_("%s: unknown extension (none)\n"),
189 filename_to_utf8(filename));
190 return LOADER_NONE;
193 ext_len = strlen(ext);
194 res = ext_to_loader(ext, ext_len);
196 if (res == NULL) {
197 LOADING_ERROR(_("%s: unknown extension\n"), filename_to_utf8(filename));
198 return LOADER_NONE;
201 if (res->loader == LOADER_DECOMP)
202 return get_decompressor(filename, ext_len);
204 return res->loader;
207 #if 0
209 * We used to blacken image pixels with alpha == 0.
210 * These pixels are invisible but may alter the bilinear filtering.
211 * We have stopped doing it since the time lost is too big for the benefit.
213 static void clean_alpha(GdkPixbuf * pixbuf)
215 guchar *pixel, *end;
217 pixel = gdk_pixbuf_get_pixels(pixbuf);
218 end = pixel + pixels_size(pixels_size);
220 for (; pixel < end; pixel += 4) {
221 if (pixel[3] == 0)
223 * alpha == 0
224 * This is not valid C since a cast cannot be a lvalue but...
226 *((guint32 *) pixel) = 0;
229 #endif
231 void set_loading(const gchar * filename)
233 /* Used if there is a segfault. */
234 g_free(loading_filename);
235 loading_filename = g_strdup(filename);
236 update_current_image_status(FALSE);
238 if (filename == NULL)
240 * Do it, now that we are no more in
241 * the currently_loading() case
243 load_later();
246 /* Wrapper: two args -> one arg. */
247 typedef struct {
248 const gchar *filename;
249 GError **error;
250 } fname_error;
252 static GdkPixbuf *load_gdk_pixbuf(fname_error * param)
254 GdkPixbuf *pixbuf = NULL;
255 loader_t loader;
257 loader = get_loader(param->filename);
258 if (loader == LOADER_DECOMP_PIXBUF)
259 pixbuf = load_compressed_pixbuf(param->filename, param->error);
261 if (*param->error)
262 return pixbuf;
264 if (pixbuf == NULL)
265 pixbuf = gdk_pixbuf_new_from_file(param->filename, param->error);
267 return pixbuf;
270 static GdkPixbuf *load_gdk_pixbuf_threaded(const gchar * filename,
271 GError ** error)
273 fname_error *param;
274 GdkPixbuf *pixbuf;
276 param = g_new(fname_error, 1);
277 param->filename = filename;
278 param->error = (error == NULL) ? g_new(GError *, 1) : error;
280 *param->error = NULL;
281 pixbuf = do_threaded((GThreadFunc) load_gdk_pixbuf, param);
283 if (pixbuf == NULL) {
284 if (error == NULL) {
286 * The caller won't handle the error, handle it here
288 if (*param->error != NULL)
289 DIALOG_MSG("%s", (*param->error)->message);
290 else
291 DIALOG_MSG(_("Cannot load %s"), filename);
293 } else
294 add_thumbnail(filename, pixbuf);
296 g_free(param);
297 return pixbuf;
300 gint pixels_size(GdkPixbuf * pixbuf)
302 /* The last rowstride may not be full. */
303 gint w = gdk_pixbuf_get_width(pixbuf);
304 gint h = gdk_pixbuf_get_height(pixbuf);
305 gint rs = gdk_pixbuf_get_rowstride(pixbuf);
306 gint nb_chan = gdk_pixbuf_get_n_channels(pixbuf);
307 gint bps = gdk_pixbuf_get_bits_per_sample(pixbuf);
309 return ((h - 1) * rs + w * ((nb_chan * bps + 7) / 8));
312 G_GNUC_PURE static gint nb_maps(gint dim)
314 gint ret = 1;
316 while (dim > rt->max_texture_size) {
317 dim *= MIPMAP_RATIO;
318 ret++;
321 return ret;
324 GlivImage *make_gliv_image(GdkPixbuf * pixbuf)
326 GlivImage *im;
328 im = gliv_image_new();
329 im->ident = NULL;
330 im->number = -1;
331 im->node = NULL;
332 im->first_image = (current_image == NULL);
334 im->width = gdk_pixbuf_get_width(pixbuf);
335 im->height = gdk_pixbuf_get_height(pixbuf);
336 im->has_alpha = gdk_pixbuf_get_has_alpha(pixbuf);
338 if (options->mipmap) {
339 gint nb_w = nb_maps(im->width);
340 gint nb_h = nb_maps(im->height);
341 im->nb_maps = MIN(nb_w, nb_h);
342 } else
343 im->nb_maps = 1;
345 im->maps = g_new(texture_map, im->nb_maps);
346 im->maps[0].pixbuf = pixbuf;
348 #if 0
349 if (im->has_alpha)
350 clean_alpha(pixbuf);
351 #endif
353 create_maps(im);
354 return im;
357 GlivImage *load_file(const gchar * filename, GError ** error)
359 GdkPixbuf *loaded_image;
360 GlivImage *im = NULL;
362 set_loading(filename_to_utf8(filename));
364 loaded_image = load_gdk_pixbuf_threaded(filename, error);
365 if (loaded_image != NULL)
366 im = make_gliv_image(loaded_image);
368 set_loading(NULL);
370 return im;