Merged older cs.po file with newest pot file.
[gliv/czech_localization.git] / src / transition.c
blob928c3642ce8db11233329aad51a42814b42c28ef
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 * Transition between images *
23 *****************************/
25 #include <string.h> /* memcpy() */
26 #include <stdio.h> /* printf(), puts() */
28 #include "gliv.h"
29 #include "transition.h"
30 #include "opengl.h"
31 #include "matrix.h"
32 #include "gliv-image.h"
33 #include "rendering.h"
34 #include "options.h"
35 #include "loading.h"
36 #include "messages.h"
39 * Define as 1 to activate the framerate counter during transitions.
40 * Set 0 as delay between steps to have a more accurate framerate.
42 #define FPS_COUNTER 0
44 extern options_struct *options;
45 extern GlivImage *current_image;
46 extern GtkWidget *gl_widget;
48 /* Whether we are executing a transition */
49 static gboolean in_transition = FALSE;
51 static void clear(void)
53 glDisable(GL_DITHER);
54 glDisable(GL_BLEND);
55 glClear(GL_COLOR_BUFFER_BIT);
56 glEnable(GL_BLEND);
57 glEnable(GL_DITHER);
60 static void draw_image(GlivImage * im, gfloat * matrix, gfloat opacity)
62 GlivImage *old_image = current_image;
63 gfloat old_matrix[8];
65 /* Backup the matrix */
66 matrix_cpy(old_matrix, NULL);
68 /* Load the desired matrix */
69 matrix_cpy(NULL, matrix);
71 glColor4f(1.0, 1.0, 1.0, opacity);
73 current_image = im;
74 draw_current_image();
76 /* Restore global parameters */
77 current_image = old_image;
78 if (matrix)
79 matrix_cpy(NULL, old_matrix);
82 /* res = big - small */
83 void diff_timeval(GTimeVal * res, GTimeVal * big, GTimeVal * small)
85 res->tv_sec = big->tv_sec - small->tv_sec;
86 if (big->tv_usec >= small->tv_usec)
87 res->tv_usec = big->tv_usec - small->tv_usec;
88 else {
89 res->tv_sec--;
90 res->tv_usec = big->tv_usec + G_USEC_PER_SEC - small->tv_usec;
94 static void transition_single_step(GdkGLDrawable * gldrawable,
95 GlivImage * im1, gfloat * matrix1,
96 GlivImage * im2, gfloat * matrix2,
97 gfloat alpha)
99 clear();
101 draw_image(im1, matrix1, 1.0 - alpha);
102 draw_image(im2, matrix2, alpha);
104 gdk_gl_drawable_swap_buffers(gldrawable);
105 gdk_gl_drawable_wait_gl(gldrawable);
109 * This is the transition used if both images lack an alpha channel and the
110 * background color is black.
111 * For the other cases, we build new images and use them in these conditions.
113 static void transition_no_alpha_black(GlivImage * im1, gfloat * matrix1,
114 GlivImage * im2, gfloat * matrix2)
116 gint steps = 0;
117 GTimeVal now, transition_start;
118 gint advance = 0;
119 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(gl_widget);
121 glEnable(GL_BLEND);
122 glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
124 g_get_current_time(&transition_start);
125 g_get_current_time(&now);
127 for (;;) {
128 gint delay = diff_timeval_us(&now, &transition_start);
129 gfloat alpha = (gfloat) delay / (options->trans_time * 1000);
131 if (alpha > 1.0)
132 break;
134 g_get_current_time(&now);
136 transition_single_step(gldrawable, im1, matrix1, im2, matrix2, alpha);
138 if (options->fps > 0) {
139 if (get_fps_limiter_delay(&now) > 0)
140 gtk_main_iteration_do(FALSE);
141 delay = get_fps_limiter_delay(&now) + advance;
142 if (delay > 0)
143 g_usleep(delay);
144 advance += get_fps_limiter_delay(&now);
146 #if FPS_COUNTER
147 printf("transition lag: %dus\n", -get_fps_limiter_delay(&now));
148 #endif
150 steps++;
153 #if FPS_COUNTER
155 gfloat usecs = (gfloat) diff_timeval_us(&now, &transition_start);
156 printf("%dx%d -> %dx%d : %d frames in %f sec => %f fps\n",
157 im1->width, im1->height, im2->width, im2->height,
158 steps, usecs / G_USEC_PER_SEC, G_USEC_PER_SEC * steps / usecs);
160 #endif
162 glColor4f(1.0, 1.0, 1.0, 1.0);
163 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
164 glDisable(GL_BLEND);
168 * If an image has an alpha channel or the background is not black,
169 * we compose it with the background in order to get a new image without
170 * an alpha channel which can be used with a black background.
172 static GlivImage *grab_image(GlivImage * im, gfloat * matrix,
173 gfloat ** new_mat, gboolean bg_is_black)
175 GlivImage *new_im;
176 gpointer data;
177 gint viewport[4], x, y, w, h;
178 GdkPixbuf *pixbuf;
179 gboolean old_mipmap;
180 gboolean old_dither;
182 *new_mat = new_matrix();
184 if (im->has_alpha == FALSE && bg_is_black) {
185 /* This image was actually OK */
186 matrix_cpy(*new_mat, matrix);
187 g_object_ref(im);
188 return im;
191 clear();
193 /* OpenGL coordinates => X coordinates */
194 flip_matrix(*new_mat, TRUE);
196 draw_image(im, matrix, 1.0);
198 /* Area where we take the screenshot */
199 #if NO_OPENGL
200 x = 0;
201 y = 0;
202 w = 640;
203 h = 480;
204 #else
205 glGetIntegerv(GL_VIEWPORT, viewport);
206 x = viewport[0];
207 y = viewport[1];
208 w = viewport[2];
209 h = viewport[3];
210 #endif
212 /* Will receive the pixels */
213 data = g_new(guint8, w * h * 3);
215 glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, data);
217 pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, FALSE, 8, w, h,
218 w * 3, (GdkPixbufDestroyNotify) g_free,
219 NULL);
221 #if 0
223 static gint id = 0;
224 gchar *base = g_path_get_basename(im->node->data);
225 gchar *filename = g_strdup_printf("%s_%d.png", base, id++);
227 g_free(base);
228 gdk_pixbuf_save(pixbuf, filename, "png", NULL, NULL);
229 g_free(filename);
231 #endif
233 /* We don't need mipmaps and dithering for this image */
234 old_mipmap = options->mipmap;
235 old_dither = options->dither;
236 options->mipmap = FALSE;
237 options->dither = FALSE;
239 new_im = make_gliv_image(pixbuf);
241 options->mipmap = old_mipmap;
242 options->dither = old_dither;
244 return new_im;
247 void transition(GlivImage * im)
249 GdkColor black;
250 gboolean bg_is_black = FALSE;
251 gchar *text;
252 gchar *base1, *base2;
253 gfloat *old_matrix = new_matrix();
254 gfloat *new_matrix = get_matrix_for_image(im);
256 in_transition = TRUE;
258 matrix_cpy(old_matrix, NULL);
259 base1 = g_path_get_basename(current_image->node->data);
260 base2 = g_path_get_basename(im->node->data);
261 text = g_strdup_printf(_("transition from `%s' to `%s'"), base1, base2);
263 g_free(base1);
264 g_free(base2);
266 set_loading(text);
267 g_free(text);
269 black.red = black.green = black.blue = 0;
271 if (!gdk_colormap_alloc_color(gdk_colormap_get_system(),
272 &black, TRUE, TRUE) == FALSE)
273 black.pixel = 0;
275 bg_is_black = gdk_color_equal(&options->bg_col, &black);
276 gdk_colormap_free_colors(gdk_colormap_get_system(), &black, 1);
278 if (current_image->has_alpha == FALSE && im->has_alpha == FALSE &&
279 bg_is_black) {
281 /* Easy case */
282 transition_no_alpha_black(current_image, old_matrix, im, new_matrix);
283 } else {
284 GdkColor orig_bg_color;
285 GlivImage *im1 = NULL, *im2 = NULL;
286 gfloat *matrix1, *matrix2;
288 printf("Transition slow case: (cur: %s, im: %s, bg: %s)\n",
289 current_image->has_alpha ? "alpha" : "no alpha",
290 im->has_alpha ? "alpha" : "no alpha",
291 bg_is_black ? "black" : "not black");
293 if (options->one_image) {
294 puts("The \"Only one image mode\" is incompatible "
295 "with slow transitions");
296 goto out;
299 im1 = grab_image(current_image, old_matrix, &matrix1, bg_is_black);
300 im2 = grab_image(im, new_matrix, &matrix2, bg_is_black);
302 /* Black background */
303 memcpy(&orig_bg_color, &options->bg_col, sizeof(GdkColor));
304 memcpy(&options->bg_col, &black, sizeof(GdkColor));
305 update_bg_color();
307 transition_no_alpha_black(im1, matrix1, im2, matrix2);
309 /* Restore the background */
310 memcpy(&options->bg_col, &orig_bg_color, sizeof(GdkColor));
311 update_bg_color();
313 g_free(matrix1);
314 g_free(matrix2);
315 g_object_unref(im1);
316 g_object_unref(im2);
318 out:
319 g_free(old_matrix);
320 g_free(new_matrix);
321 in_transition = FALSE;
322 set_loading(NULL);
325 gboolean is_in_transition(void)
327 return in_transition;