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() */
29 #include "transition.h"
32 #include "gliv-image.h"
33 #include "rendering.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.
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)
55 glClear(GL_COLOR_BUFFER_BIT
);
60 static void draw_image(GlivImage
* im
, gfloat
* matrix
, gfloat opacity
)
62 GlivImage
*old_image
= current_image
;
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
);
76 /* Restore global parameters */
77 current_image
= old_image
;
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
;
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
,
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
)
117 GTimeVal now
, transition_start
;
119 GdkGLDrawable
*gldrawable
= gtk_widget_get_gl_drawable(gl_widget
);
122 glBlendFunc(GL_SRC_ALPHA
, GL_DST_ALPHA
);
124 g_get_current_time(&transition_start
);
125 g_get_current_time(&now
);
128 gint delay
= diff_timeval_us(&now
, &transition_start
);
129 gfloat alpha
= (gfloat
) delay
/ (options
->trans_time
* 1000);
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
;
144 advance
+= get_fps_limiter_delay(&now
);
147 printf("transition lag: %dus\n", -get_fps_limiter_delay(&now
));
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
);
162 glColor4f(1.0, 1.0, 1.0, 1.0);
163 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
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
)
177 gint viewport
[4], x
, y
, w
, h
;
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
);
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 */
205 glGetIntegerv(GL_VIEWPORT
, viewport
);
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
,
224 gchar
*base
= g_path_get_basename(im
->node
->data
);
225 gchar
*filename
= g_strdup_printf("%s_%d.png", base
, id
++);
228 gdk_pixbuf_save(pixbuf
, filename
, "png", NULL
, NULL
);
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
;
247 void transition(GlivImage
* im
)
250 gboolean bg_is_black
= FALSE
;
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
);
269 black
.red
= black
.green
= black
.blue
= 0;
271 if (!gdk_colormap_alloc_color(gdk_colormap_get_system(),
272 &black
, TRUE
, TRUE
) == FALSE
)
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
&&
282 transition_no_alpha_black(current_image
, old_matrix
, im
, new_matrix
);
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");
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
));
307 transition_no_alpha_black(im1
, matrix1
, im2
, matrix2
);
309 /* Restore the background */
310 memcpy(&options
->bg_col
, &orig_bg_color
, sizeof(GdkColor
));
321 in_transition
= FALSE
;
325 gboolean
is_in_transition(void)
327 return in_transition
;