added autoconf test for clutter
[geeqie.git] / src / renderer-clutter.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  * Copyright (C) 2008 - 2012 The Geeqie Team
5  *
6  * Author: John Ellis
7  * Author: Vladimir Nadvornik
8  *
9  * This software is released under the GNU General Public License (GNU GPL).
10  * Please read the included file COPYING for more information.
11  * This software comes with no warranty of any kind, use at your own risk!
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <math.h>
18
19 #include "main.h"
20 #include "pixbuf-renderer.h"
21 #include "renderer-clutter.h"
22
23 #include "intl.h"
24 #include "layout.h"
25
26 #include <gtk/gtk.h>
27
28 #ifdef HAVE_CLUTTER
29
30 #include <clutter/clutter.h>
31
32 #include <clutter-gtk/clutter-gtk.h>
33
34
35
36 #define GQ_BUILD 1
37
38 #ifdef GQ_BUILD
39 #include "main.h"
40 #include "pixbuf_util.h"
41 #include "exif.h"
42 #else
43 typedef enum {
44         EXIF_ORIENTATION_UNKNOWN        = 0,
45         EXIF_ORIENTATION_TOP_LEFT       = 1,
46         EXIF_ORIENTATION_TOP_RIGHT      = 2,
47         EXIF_ORIENTATION_BOTTOM_RIGHT   = 3,
48         EXIF_ORIENTATION_BOTTOM_LEFT    = 4,
49         EXIF_ORIENTATION_LEFT_TOP       = 5,
50         EXIF_ORIENTATION_RIGHT_TOP      = 6,
51         EXIF_ORIENTATION_RIGHT_BOTTOM   = 7,
52         EXIF_ORIENTATION_LEFT_BOTTOM    = 8
53 } ExifOrientationType;
54 #endif
55
56
57 typedef struct _OverlayData OverlayData;
58 struct _OverlayData
59 {
60         gint id;
61
62         GdkPixbuf *pixbuf;
63         GdkWindow *window;
64
65         gint x;
66         gint y;
67
68         OverlayRendererFlags flags;
69 };
70
71 typedef struct _RendererClutter RendererClutter;
72
73 struct _RendererClutter
74 {
75         RendererFuncs f;
76         PixbufRenderer *pr;
77
78         
79         gint stereo_mode;
80         gint stereo_off_x;
81         gint stereo_off_y;
82         
83         gint x_scroll;  /* allow local adjustment and mirroring */
84         gint y_scroll;
85         
86         GtkWidget *widget; /* widget and stage may be shared with other renderers */
87         ClutterActor *stage;
88         ClutterActor *texture;
89         ClutterActor *group;
90 };
91
92 static void rc_sync_actor(RendererClutter *rc)
93 {
94         PixbufRenderer *pr = rc->pr;
95         gint anchor_x = 0;
96         gint anchor_y = 0;
97         
98         clutter_actor_set_anchor_point(CLUTTER_ACTOR(rc->texture), 0, 0);
99
100         printf("scale %d %d\n", rc->pr->width, rc->pr->height);
101         printf("pos   %d %d        %d %d\n", rc->pr->x_offset, rc->pr->y_offset, rc->x_scroll, rc->y_scroll);
102         
103         switch (pr->orientation)
104                 {
105                 case EXIF_ORIENTATION_TOP_LEFT:
106                         /* normal  */
107                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
108                                                 CLUTTER_Z_AXIS,
109                                                 0, 0, 0, 0);
110                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
111                                                 CLUTTER_Y_AXIS,
112                                                 0, 0, 0, 0);
113                         clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->width, pr->height);
114                         anchor_x = 0;
115                         anchor_y = 0;
116                         break;
117                 case EXIF_ORIENTATION_TOP_RIGHT:
118                         /* mirrored */
119                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
120                                                 CLUTTER_Z_AXIS,
121                                                 0, 0, 0, 0);
122                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
123                                                 CLUTTER_Y_AXIS,
124                                                 180, 0, 0, 0);
125                         clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->width, pr->height);
126                         anchor_x = pr->width;
127                         anchor_y = 0;
128                         break;
129                 case EXIF_ORIENTATION_BOTTOM_RIGHT:
130                         /* upside down */
131                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
132                                                 CLUTTER_Z_AXIS,
133                                                 180, 0, 0, 0);
134                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
135                                                 CLUTTER_Y_AXIS,
136                                                 0, 0, 0, 0);
137                         clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->width, pr->height);
138                         anchor_x = pr->width;
139                         anchor_y = pr->height;
140                         break;
141                 case EXIF_ORIENTATION_BOTTOM_LEFT:
142                         /* flipped */
143                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
144                                                 CLUTTER_Z_AXIS,
145                                                 180, 0, 0, 0);
146                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
147                                                 CLUTTER_Y_AXIS,
148                                                 180, 0, 0, 0);
149                         clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->width, pr->height);
150                         anchor_x = 0;
151                         anchor_y = pr->height;
152                         break;
153                 case EXIF_ORIENTATION_LEFT_TOP:
154                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
155                                                 CLUTTER_Z_AXIS,
156                                                 -90, 0, 0, 0);
157                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
158                                                 CLUTTER_Y_AXIS,
159                                                 180, 0, 0, 0);
160                         clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->height, pr->width);
161                         anchor_x = 0;
162                         anchor_y = 0;
163                         break;
164                 case EXIF_ORIENTATION_RIGHT_TOP:
165                         /* rotated -90 (270) */
166                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
167                                                 CLUTTER_Z_AXIS,
168                                                 -90, 0, 0, 0);
169                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
170                                                 CLUTTER_Y_AXIS,
171                                                 0, 0, 0, 0);
172                         clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->height, pr->width);
173                         anchor_x = 0;
174                         anchor_y = pr->height;
175                         break;
176                 case EXIF_ORIENTATION_RIGHT_BOTTOM:
177                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
178                                                 CLUTTER_Z_AXIS,
179                                                 90, 0, 0, 0);
180                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
181                                                 CLUTTER_Y_AXIS,
182                                                 180, 0, 0, 0);
183                         clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->height, pr->width);
184                         anchor_x = pr->width;
185                         anchor_y = pr->height;
186                         break;
187                 case EXIF_ORIENTATION_LEFT_BOTTOM:
188                         /* rotated 90 */
189                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
190                                                 CLUTTER_Z_AXIS,
191                                                 90, 0, 0, 0);
192                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
193                                                 CLUTTER_Y_AXIS,
194                                                 0, 0, 0, 0);
195                         clutter_actor_set_size(CLUTTER_ACTOR(rc->texture), pr->height, pr->width);
196                         anchor_x = pr->width;
197                         anchor_y = 0;
198                         break;
199                 default:
200                         /* The other values are out of range */
201                         break;
202                 }
203         
204         clutter_actor_set_position(CLUTTER_ACTOR(rc->texture), 
205                                 pr->x_offset - pr->x_scroll + anchor_x, 
206                                 pr->y_offset - pr->y_scroll + anchor_y);
207
208 }
209
210
211 static void renderer_area_changed(void *renderer, gint src_x, gint src_y, gint src_w, gint src_h)
212 {
213         RendererClutter *rc = (RendererClutter *)renderer;
214         PixbufRenderer *pr = rc->pr;
215         
216         
217         
218         printf("renderer_area_changed %d %d %d %d\n", src_x, src_y, src_w, src_h);
219         if (pr->pixbuf)
220                 {
221                 CoglHandle texture = clutter_texture_get_cogl_texture(CLUTTER_TEXTURE(rc->texture));
222                 
223                 cogl_texture_set_region(texture,
224                                         src_x,
225                                         src_y,
226                                         src_x,
227                                         src_y,
228                                         src_w,
229                                         src_h,
230                                         src_w,
231                                         src_h,
232                                         gdk_pixbuf_get_has_alpha(pr->pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
233                                         gdk_pixbuf_get_rowstride(pr->pixbuf),
234                                         gdk_pixbuf_get_pixels(pr->pixbuf));
235                 clutter_actor_queue_redraw(CLUTTER_ACTOR(rc->texture));
236                 }
237
238 }
239
240 static void renderer_update_pixbuf(void *renderer, gboolean lazy)
241 {
242         RendererClutter *rc = (RendererClutter *)renderer;
243         PixbufRenderer *pr = rc->pr;
244         
245         if (pr->pixbuf)
246                 {
247                 printf("renderer_update_pixbuf\n");
248                 
249                 /* FIXME use CoglMaterial with multiple textures for background, color management, anaglyph, ... */
250                 CoglHandle texture = cogl_texture_new_with_size(gdk_pixbuf_get_width(pr->pixbuf),
251                                                                 gdk_pixbuf_get_height(pr->pixbuf),
252                                                                 COGL_TEXTURE_NONE,
253                                                                 gdk_pixbuf_get_has_alpha(pr->pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888);
254
255                 if (texture != COGL_INVALID_HANDLE)
256                         {
257                         clutter_texture_set_cogl_texture(CLUTTER_TEXTURE(rc->texture), texture);
258                         cogl_handle_unref(texture);
259                         }
260                 if (!lazy)
261                         {
262                         renderer_area_changed(renderer, 0, 0, gdk_pixbuf_get_width(pr->pixbuf), gdk_pixbuf_get_height(pr->pixbuf));
263                         }
264                 }
265
266
267         printf("renderer_update_pixbuf\n");
268         rc_sync_actor(rc);
269 }
270
271
272
273 static void renderer_update_zoom(void *renderer, gboolean lazy)
274 {
275         RendererClutter *rc = (RendererClutter *)renderer;
276         PixbufRenderer *pr = rc->pr;
277
278         printf("renderer_update_zoom\n");
279         rc_sync_actor(rc);
280 }
281
282 static void renderer_invalidate_region(void *renderer, gint x, gint y, gint w, gint h)
283 {
284 }
285
286 static void renderer_overlay_draw(void *renderer, gint x, gint y, gint w, gint h)
287 {
288 }
289
290 static void renderer_overlay_add(void *renderer, gint x, gint y, gint w, gint h)
291 {
292 }
293
294 static void renderer_overlay_set(void *renderer, gint x, gint y, gint w, gint h)
295 {
296 }
297
298 static void renderer_overlay_get(void *renderer, gint x, gint y, gint w, gint h)
299 {
300 }
301
302 static void renderer_update_sizes(void *renderer)
303 {
304         RendererClutter *rc = (RendererClutter *)renderer;
305         ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; 
306
307         rc->stereo_off_x = 0;
308         rc->stereo_off_y = 0;
309         
310         if (rc->stereo_mode & PR_STEREO_RIGHT) 
311                 {
312                 if (rc->stereo_mode & PR_STEREO_HORIZ) 
313                         {
314                         rc->stereo_off_x = rc->pr->viewport_width;
315                         }
316                 else if (rc->stereo_mode & PR_STEREO_VERT) 
317                         {
318                         rc->stereo_off_y = rc->pr->viewport_height;
319                         }
320                 else if (rc->stereo_mode & PR_STEREO_FIXED) 
321                         {
322                         rc->stereo_off_x = rc->pr->stereo_fixed_x_right;
323                         rc->stereo_off_y = rc->pr->stereo_fixed_y_right;
324                         }
325                 }
326         else
327                 {
328                 if (rc->stereo_mode & PR_STEREO_FIXED) 
329                         {
330                         rc->stereo_off_x = rc->pr->stereo_fixed_x_left;
331                         rc->stereo_off_y = rc->pr->stereo_fixed_y_left;
332                         }
333                 }
334         DEBUG_1("update size: %p  %d %d   %d %d", rc, rc->stereo_off_x, rc->stereo_off_y, rc->pr->viewport_width, rc->pr->viewport_height);
335
336         printf("renderer_update_sizes  scale %d %d\n", rc->pr->width, rc->pr->height);
337
338         clutter_stage_set_color(CLUTTER_STAGE(rc->stage), &stage_color);
339
340
341         clutter_actor_set_size(rc->group, rc->pr->viewport_width, rc->pr->viewport_height);
342         clutter_actor_set_position(rc->group, rc->stereo_off_x, rc->stereo_off_y);
343         
344         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->group),
345                                                 CLUTTER_Y_AXIS,
346                                                 (rc->stereo_mode & PR_STEREO_MIRROR) ? 180 : 0, 
347                                                 rc->pr->viewport_width / 2.0, 0, 0);
348
349         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->group),
350                                                 CLUTTER_X_AXIS,
351                                                 (rc->stereo_mode & PR_STEREO_FLIP) ? 180 : 0,
352                                                 0, rc->pr->viewport_height / 2.0, 0);
353
354         rc_sync_actor(rc);
355 }
356
357 static void renderer_scroll(void *renderer, gint x_off, gint y_off)
358 {
359         printf("renderer_scroll\n");
360         RendererClutter *rc = (RendererClutter *)renderer;
361         PixbufRenderer *pr = rc->pr;
362
363         rc_sync_actor(rc);
364 }
365
366 static void renderer_stereo_set(void *renderer, gint stereo_mode)
367 {
368         RendererClutter *rc = (RendererClutter *)renderer;
369
370         rc->stereo_mode = stereo_mode;
371 }
372
373 static void renderer_free(void *renderer)
374 {
375         RendererClutter *rc = (RendererClutter *)renderer;
376         GtkWidget *widget = gtk_bin_get_child(GTK_BIN(rc->pr));
377         if (widget)
378                 {
379                 /* widget still exists */
380                 clutter_actor_destroy(rc->group);
381                 if (clutter_group_get_n_children(CLUTTER_GROUP(rc->stage)) == 0)
382                         {
383                         printf("destroy %p\n", rc->widget);
384                         /* this was the last user */
385                         gtk_widget_destroy(rc->widget);
386                         }
387                 else
388                         {
389                         printf("keep %p\n", rc->widget);
390                         g_object_unref(G_OBJECT(rc->widget));
391                         }
392                 }
393         g_free(rc);
394 }
395
396 RendererFuncs *renderer_clutter_new(PixbufRenderer *pr)
397 {
398         RendererClutter *rc = g_new0(RendererClutter, 1);
399         
400         rc->pr = pr;
401         
402         rc->f.area_changed = renderer_area_changed;
403         rc->f.update_pixbuf = renderer_update_pixbuf;
404         rc->f.free = renderer_free;
405         rc->f.update_zoom = renderer_update_zoom;
406         rc->f.invalidate_region = renderer_invalidate_region;
407         rc->f.scroll = renderer_scroll;
408         rc->f.update_sizes = renderer_update_sizes;
409
410
411         rc->f.overlay_add = renderer_overlay_add;
412         rc->f.overlay_set = renderer_overlay_set;
413         rc->f.overlay_get = renderer_overlay_get;
414         rc->f.overlay_draw = renderer_overlay_draw;
415
416         rc->f.stereo_set = renderer_stereo_set;
417         
418         
419         rc->stereo_mode = 0;
420         rc->stereo_off_x = 0;
421         rc->stereo_off_y = 0;
422
423
424         rc->widget = gtk_bin_get_child(GTK_BIN(rc->pr));
425         
426         if (rc->widget)
427                 {
428                 if (!GTK_CLUTTER_IS_EMBED(rc->widget))
429                         {
430                         g_free(rc);
431                         DEBUG_0("pixbuf renderer has a child of other type than gtk_clutter_embed");
432                         return NULL;
433                         }
434                 }
435         else 
436                 {
437                 rc->widget = gtk_clutter_embed_new();
438                 gtk_container_add(GTK_CONTAINER(rc->pr), rc->widget);
439                 }
440                 
441         gtk_event_box_set_above_child (GTK_EVENT_BOX(rc->pr), TRUE);
442         rc->stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (rc->widget));
443         
444         rc->group = clutter_group_new();
445         clutter_container_add_actor(CLUTTER_CONTAINER(rc->stage), rc->group);
446         clutter_actor_set_clip_to_allocation(CLUTTER_ACTOR(rc->group), TRUE);
447   
448         rc->texture = gtk_clutter_texture_new ();
449         clutter_container_add_actor(CLUTTER_CONTAINER(rc->group), rc->texture);
450         g_object_ref(G_OBJECT(rc->widget));
451   
452         gtk_widget_show(rc->widget);
453         return (RendererFuncs *) rc;
454 }
455
456 #endif 
457 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */