draw background checkboard using fragment shader
[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 #define GET_RIGHT_PIXBUF_OFFSET(rc) \
57         (( (rc->stereo_mode & PR_STEREO_RIGHT) && !(rc->stereo_mode & PR_STEREO_SWAP)) || \
58          (!(rc->stereo_mode & PR_STEREO_RIGHT) &&  (rc->stereo_mode & PR_STEREO_SWAP)) ?  \
59           rc->pr->stereo_pixbuf_offset_right : rc->pr->stereo_pixbuf_offset_left )
60
61 #define GET_LEFT_PIXBUF_OFFSET(rc) \
62         ((!(rc->stereo_mode & PR_STEREO_RIGHT) && !(rc->stereo_mode & PR_STEREO_SWAP)) || \
63          ( (rc->stereo_mode & PR_STEREO_RIGHT) &&  (rc->stereo_mode & PR_STEREO_SWAP)) ?  \
64           rc->pr->stereo_pixbuf_offset_right : rc->pr->stereo_pixbuf_offset_left )
65
66
67 typedef struct _OverlayData OverlayData;
68 struct _OverlayData
69 {
70         gint id;
71
72         GdkPixbuf *pixbuf;
73         ClutterActor *actor;
74
75         gint x;
76         gint y;
77
78         OverlayRendererFlags flags;
79 };
80
81 typedef struct _RendererClutter RendererClutter;
82
83 struct _RendererClutter
84 {
85         RendererFuncs f;
86         PixbufRenderer *pr;
87
88         
89         gint stereo_mode;
90         gint stereo_off_x;
91         gint stereo_off_y;
92         
93         
94         GList *pending_updates;
95         gint idle_update;
96         
97         GList *overlay_list;
98         
99         GtkWidget *widget; /* widget and stage may be shared with other renderers */
100         ClutterActor *stage;
101         ClutterActor *texture;
102         ClutterActor *group;
103 };
104
105 typedef struct _RendererClutterAreaParam RendererClutterAreaParam;
106 struct _RendererClutterAreaParam {
107         RendererClutter *rc;
108         gint x;
109         gint y;
110         gint w;
111         gint h;
112 };
113
114 static void rc_set_shader(CoglHandle material)
115 {
116   CoglHandle shader;
117   CoglHandle program;
118
119   shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
120   cogl_shader_source (shader,
121   "vec3 checker(vec2 texc, vec3 color0, vec3 color1)"
122   "{"
123   "  if (mod(int(floor(texc.x) + floor(texc.y)), 2) == 0)"
124   "    return color0;"
125   "  else"
126   "    return color1;"
127   "}"
128   
129   "uniform sampler2D tex;"
130   "void main(void)"
131   "{"
132   "    vec3 bg = checker(gl_FragCoord.xy / 16, vec3(0.6, 0.6, 0.6), vec3(0.4, 0.4, 0.4));"
133   "    vec4 img4 = texture2D(tex, gl_TexCoord[0].xy);"
134   "    vec3 img3 = img4.rgb;"
135   "    gl_FragColor = vec4(img3 * img4.a + bg * (1.0 - img4.a), 1.0);"
136   "}"
137   );
138   cogl_shader_compile(shader);
139   gchar *err = cogl_shader_get_info_log(shader);
140   printf("%s\n",err);
141   g_free(err);
142
143   program = cogl_create_program ();
144   cogl_program_attach_shader (program, shader);
145   cogl_handle_unref (shader);
146   cogl_program_link (program);
147
148   gint uniform_no = cogl_program_get_uniform_location (program, "tex");
149   cogl_program_set_uniform_1i (program, uniform_no, 0);
150
151   cogl_material_set_user_program (material, program);
152   cogl_handle_unref (program);
153 }
154
155
156 static void rc_sync_actor(RendererClutter *rc)
157 {
158         PixbufRenderer *pr = rc->pr;
159         gint anchor_x = 0;
160         gint anchor_y = 0;
161         
162         clutter_actor_set_anchor_point(CLUTTER_ACTOR(rc->texture), 0, 0);
163
164         printf("scale %d %d\n", rc->pr->width, rc->pr->height);
165         printf("pos   %d %d\n", rc->pr->x_offset, rc->pr->y_offset);
166         
167         clutter_actor_set_scale(CLUTTER_ACTOR(rc->texture), 
168                                 (gfloat)pr->width / pr->image_width,
169                                 (gfloat)pr->height / pr->image_height);
170                                 
171         switch (pr->orientation)
172                 {
173                 case EXIF_ORIENTATION_TOP_LEFT:
174                         /* normal  */
175                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
176                                                 CLUTTER_Z_AXIS,
177                                                 0, 0, 0, 0);
178                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
179                                                 CLUTTER_Y_AXIS,
180                                                 0, 0, 0, 0);
181                         anchor_x = 0;
182                         anchor_y = 0;
183                         break;
184                 case EXIF_ORIENTATION_TOP_RIGHT:
185                         /* mirrored */
186                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
187                                                 CLUTTER_Z_AXIS,
188                                                 0, 0, 0, 0);
189                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
190                                                 CLUTTER_Y_AXIS,
191                                                 180, 0, 0, 0);
192                         anchor_x = pr->width;
193                         anchor_y = 0;
194                         break;
195                 case EXIF_ORIENTATION_BOTTOM_RIGHT:
196                         /* upside down */
197                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
198                                                 CLUTTER_Z_AXIS,
199                                                 180, 0, 0, 0);
200                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
201                                                 CLUTTER_Y_AXIS,
202                                                 0, 0, 0, 0);
203                         anchor_x = pr->width;
204                         anchor_y = pr->height;
205                         break;
206                 case EXIF_ORIENTATION_BOTTOM_LEFT:
207                         /* flipped */
208                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
209                                                 CLUTTER_Z_AXIS,
210                                                 180, 0, 0, 0);
211                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
212                                                 CLUTTER_Y_AXIS,
213                                                 180, 0, 0, 0);
214                         anchor_x = 0;
215                         anchor_y = pr->height;
216                         break;
217                 case EXIF_ORIENTATION_LEFT_TOP:
218                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
219                                                 CLUTTER_Z_AXIS,
220                                                 -90, 0, 0, 0);
221                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
222                                                 CLUTTER_Y_AXIS,
223                                                 180, 0, 0, 0);
224                         anchor_x = 0;
225                         anchor_y = 0;
226                         break;
227                 case EXIF_ORIENTATION_RIGHT_TOP:
228                         /* rotated -90 (270) */
229                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
230                                                 CLUTTER_Z_AXIS,
231                                                 -90, 0, 0, 0);
232                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
233                                                 CLUTTER_Y_AXIS,
234                                                 0, 0, 0, 0);
235                         anchor_x = 0;
236                         anchor_y = pr->height;
237                         break;
238                 case EXIF_ORIENTATION_RIGHT_BOTTOM:
239                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
240                                                 CLUTTER_Z_AXIS,
241                                                 90, 0, 0, 0);
242                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
243                                                 CLUTTER_Y_AXIS,
244                                                 180, 0, 0, 0);
245                         anchor_x = pr->width;
246                         anchor_y = pr->height;
247                         break;
248                 case EXIF_ORIENTATION_LEFT_BOTTOM:
249                         /* rotated 90 */
250                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
251                                                 CLUTTER_Z_AXIS,
252                                                 90, 0, 0, 0);
253                         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->texture),
254                                                 CLUTTER_Y_AXIS,
255                                                 0, 0, 0, 0);
256                         anchor_x = pr->width;
257                         anchor_y = 0;
258                         break;
259                 default:
260                         /* The other values are out of range */
261                         break;
262                 }
263         
264         clutter_actor_set_position(CLUTTER_ACTOR(rc->texture), 
265                                 pr->x_offset - pr->x_scroll + anchor_x, 
266                                 pr->y_offset - pr->y_scroll + anchor_y);
267
268 }
269
270
271 static void renderer_area_clip_add(RendererClutter *rc, gfloat x, gfloat y, gfloat w, gfloat h)
272 {
273         PixbufRenderer *pr = rc->pr;
274         gfloat x2, y2;
275         gfloat clip_x, clip_y, clip_w, clip_h, clip_x2, clip_y2;
276         
277         x2 = x + w;
278         y2 = y + h;
279         
280         clutter_actor_get_clip(rc->texture, &clip_x, &clip_y, &clip_w, &clip_h);
281         
282         clip_x2 = clip_x + clip_w;
283         clip_y2 = clip_y + clip_h;
284         
285         if (clip_x > x) clip_x = x;
286         if (clip_x2 < x2) clip_x2 = x2;
287         if (clip_y > y) clip_y = y;
288         if (clip_y2 < y2) clip_y2 = y2;
289         
290         clip_w = clip_x2 - clip_x;
291         clip_h = clip_y2 - clip_y;
292         
293         printf("clip %f %f %f %f\n", clip_x, clip_y, clip_w, clip_h);
294         clutter_actor_set_clip(rc->texture, clip_x, clip_y, clip_w, clip_h);
295 }
296
297 #define MAX_REGION_AREA (32768 * 1024)
298
299 static gboolean renderer_area_changed_cb(gpointer data)
300 {
301         RendererClutter *rc = (RendererClutter *)data;
302         PixbufRenderer *pr = rc->pr;
303         
304         RendererClutterAreaParam *par = rc->pending_updates->data;
305         
306         gint h = MAX_REGION_AREA / par->w;
307         if (h == 0) h = 1;
308         if (h > par->h) h = par->h;
309         
310         
311         printf("renderer_area_changed_cb %d %d %d %d  (%d)\n", par->x, par->y, par->w, h, par->h);
312         DEBUG_0("%s upload start", get_exec_time());
313         if (pr->pixbuf)
314                 {
315                 CoglHandle texture = clutter_texture_get_cogl_texture(CLUTTER_TEXTURE(rc->texture));
316                 
317                 cogl_texture_set_region(texture,
318                                         par->x + GET_RIGHT_PIXBUF_OFFSET(rc),
319                                         par->y,
320                                         par->x,
321                                         par->y,
322                                         par->w,
323                                         h,
324                                         par->w,
325                                         h,
326                                         gdk_pixbuf_get_has_alpha(pr->pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
327                                         gdk_pixbuf_get_rowstride(pr->pixbuf),
328                                         gdk_pixbuf_get_pixels(pr->pixbuf));
329                 }
330         DEBUG_0("%s upload end", get_exec_time());
331         renderer_area_clip_add(rc, par->x, par->y, par->w, h);
332
333                 
334         par->y += h;
335         par->h -= h;
336         
337         if (par->h == 0)
338                 {
339                 rc->pending_updates = g_list_remove(rc->pending_updates, par);
340                 g_free(par);
341                 }
342         if (!rc->pending_updates)
343                 {
344                 clutter_actor_queue_redraw(CLUTTER_ACTOR(rc->texture));
345                 rc->idle_update = 0;
346                 return FALSE;
347                 }
348         return TRUE;
349 }
350
351
352 static void renderer_area_changed(void *renderer, gint src_x, gint src_y, gint src_w, gint src_h)
353 {
354         RendererClutter *rc = (RendererClutter *)renderer;
355         PixbufRenderer *pr = rc->pr;
356         RendererClutterAreaParam *par;
357
358         gint width = gdk_pixbuf_get_width(pr->pixbuf);
359         gint height = gdk_pixbuf_get_height(pr->pixbuf);
360                 
361         if (pr->stereo_data == STEREO_PIXBUF_SBS || pr->stereo_data == STEREO_PIXBUF_CROSS) 
362                         {
363                         width /= 2;
364                         }
365         
366         if (!pr_clip_region(src_x, src_y, src_w, src_h,
367                             GET_RIGHT_PIXBUF_OFFSET(rc), 0, width, height,
368                             &src_x, &src_y, &src_w, &src_h)) return;
369         
370         par = g_new0(RendererClutterAreaParam, 1);
371         par->rc = rc;
372         par->x = src_x - GET_RIGHT_PIXBUF_OFFSET(rc);
373         par->y = src_y;
374         par->w = src_w;
375         par->h = src_h;
376         rc->pending_updates = g_list_append(rc->pending_updates, par);
377         if (!rc->idle_update) 
378                 {
379                 rc->idle_update = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, renderer_area_changed_cb, rc, NULL);
380                 }
381 }
382
383 static void renderer_remove_pending_updates(RendererClutter *rc)
384 {
385         if (rc->idle_update) g_idle_remove_by_data(rc);
386         rc->idle_update = 0;
387         while (rc->pending_updates)
388                 {
389                 RendererClutterAreaParam *par = rc->pending_updates->data;
390                 rc->pending_updates = g_list_remove(rc->pending_updates, par);
391                 g_free(par);
392                 }
393 }
394
395 static void renderer_update_pixbuf(void *renderer, gboolean lazy)
396 {
397         RendererClutter *rc = (RendererClutter *)renderer;
398         PixbufRenderer *pr = rc->pr;
399         
400         renderer_remove_pending_updates(rc);
401         
402         if (pr->pixbuf)
403                 {
404                 gint width = gdk_pixbuf_get_width(pr->pixbuf);
405                 gint height = gdk_pixbuf_get_height(pr->pixbuf);
406                 
407                 gint prev_width, prev_height;
408                 
409                 if (pr->stereo_data == STEREO_PIXBUF_SBS || pr->stereo_data == STEREO_PIXBUF_CROSS) 
410                         {
411                         width /= 2;
412                         }
413
414                 
415                 printf("renderer_update_pixbuf\n");
416                 clutter_texture_get_base_size(CLUTTER_TEXTURE(rc->texture), &prev_width, &prev_height);
417                 printf("change from %d %d to %d %d\n", prev_width, prev_height, width, height);
418                 
419                 if (width != prev_width || height != prev_height)
420                         {
421                         /* FIXME use CoglMaterial with multiple textures for background, color management, anaglyph, ... */
422                         CoglHandle texture = cogl_texture_new_with_size(width,
423                                                                         height,
424                                                                         COGL_TEXTURE_NO_AUTO_MIPMAP,
425                                                                         gdk_pixbuf_get_has_alpha(pr->pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888);
426
427                         if (texture != COGL_INVALID_HANDLE)
428                                 {
429                                 clutter_texture_set_cogl_texture(CLUTTER_TEXTURE(rc->texture), texture);
430                                 cogl_handle_unref(texture);
431                                 }
432                         }
433                 clutter_actor_set_clip(rc->texture, 0, 0, 0, 0); /* visible area is extended as area_changed events arrive */
434                 if (!lazy)
435                         {
436                         renderer_area_changed(renderer, GET_RIGHT_PIXBUF_OFFSET(rc), 0, width, height);
437                         }
438                 }
439
440
441         printf("renderer_update_pixbuf\n");
442         rc_sync_actor(rc);
443 }
444
445
446
447 static void renderer_update_zoom(void *renderer, gboolean lazy)
448 {
449         RendererClutter *rc = (RendererClutter *)renderer;
450         PixbufRenderer *pr = rc->pr;
451
452         printf("renderer_update_zoom\n");
453         rc_sync_actor(rc);
454 }
455
456 static void renderer_invalidate_region(void *renderer, gint x, gint y, gint w, gint h)
457 {
458 }
459
460 static OverlayData *rc_overlay_find(RendererClutter *rc, gint id)
461 {
462         GList *work;
463
464         work = rc->overlay_list;
465         while (work)
466                 {
467                 OverlayData *od = work->data;
468                 work = work->next;
469
470                 if (od->id == id) return od;
471                 }
472
473         return NULL;
474 }
475
476 static void rc_overlay_actor_destroy_cb(ClutterActor *actor, gpointer user_data)
477 {
478         OverlayData *od = user_data;
479         od->actor = NULL;
480 }
481
482 static void rc_overlay_free(RendererClutter *rc, OverlayData *od)
483 {
484         rc->overlay_list = g_list_remove(rc->overlay_list, od);
485
486         if (od->pixbuf) g_object_unref(G_OBJECT(od->pixbuf));
487         if (od->actor) clutter_actor_destroy(od->actor);
488         g_free(od);
489 }
490
491 static void rc_overlay_update_position(RendererClutter *rc, OverlayData *od)
492 {
493         gint px, py, pw, ph;
494
495         pw = gdk_pixbuf_get_width(od->pixbuf);
496         ph = gdk_pixbuf_get_height(od->pixbuf);
497         px = od->x;
498         py = od->y;
499
500         if (od->flags & OVL_RELATIVE)
501                 {
502                 if (px < 0) px = rc->pr->viewport_width - pw + px;
503                 if (py < 0) py = rc->pr->viewport_height - ph + py;
504                 }
505         if (od->actor) clutter_actor_set_position(od->actor, px, py);
506 }
507
508 static void rc_overlay_update_positions(RendererClutter *rc)
509 {
510         GList *work;
511
512         work = rc->overlay_list;
513         while (work)
514                 {
515                 OverlayData *od = work->data;
516                 work = work->next;
517
518                 rc_overlay_update_position(rc, od);
519                 }
520 }
521
522 static void rc_overlay_free_all(RendererClutter *rc)
523 {
524         GList *work;
525
526         work = rc->overlay_list;
527         while (work)
528                 {
529                 OverlayData *od = work->data;
530                 work = work->next;
531
532                 rc_overlay_free(rc, od);
533                 }
534 }
535
536
537 static void renderer_overlay_draw(void *renderer, gint x, gint y, gint w, gint h)
538 {
539 }
540
541 static gint renderer_overlay_add(void *renderer, GdkPixbuf *pixbuf, gint x, gint y, OverlayRendererFlags flags)
542 {
543         RendererClutter *rc = (RendererClutter *)renderer;
544         PixbufRenderer *pr = rc->pr;
545         OverlayData *od;
546         gint id;
547
548         g_return_val_if_fail(IS_PIXBUF_RENDERER(pr), -1);
549         g_return_val_if_fail(pixbuf != NULL, -1);
550
551         id = 1;
552         while (rc_overlay_find(rc, id)) id++;
553
554         od = g_new0(OverlayData, 1);
555         od->id = id;
556         od->pixbuf = pixbuf;
557         g_object_ref(G_OBJECT(od->pixbuf));
558         od->x = x;
559         od->y = y;
560         od->flags = flags;
561         
562         od->actor = gtk_clutter_texture_new();
563         g_signal_connect (od->actor, "destroy", G_CALLBACK(rc_overlay_actor_destroy_cb), od);
564         
565         gtk_clutter_texture_set_from_pixbuf(GTK_CLUTTER_TEXTURE (od->actor), pixbuf, NULL);
566         clutter_container_add_actor(CLUTTER_CONTAINER(rc->group), od->actor);
567
568         rc->overlay_list = g_list_append(rc->overlay_list, od);
569         rc_overlay_update_position(rc, od);
570
571         return od->id;
572 }
573
574 static void renderer_overlay_set(void *renderer, gint id, GdkPixbuf *pixbuf, gint x, gint y)
575 {
576         RendererClutter *rc = (RendererClutter *)renderer;
577         PixbufRenderer *pr = rc->pr;
578         OverlayData *od;
579
580         g_return_if_fail(IS_PIXBUF_RENDERER(pr));
581
582         od = rc_overlay_find(rc, id);
583         if (!od) return;
584
585         if (pixbuf)
586                 {
587                 g_object_ref(G_OBJECT(pixbuf));
588                 g_object_unref(G_OBJECT(od->pixbuf));
589                 od->pixbuf = pixbuf;
590
591                 od->x = x;
592                 od->y = y;
593
594                 if (od->actor) gtk_clutter_texture_set_from_pixbuf(GTK_CLUTTER_TEXTURE(od->actor), pixbuf, NULL);
595                 rc_overlay_update_position(rc, od);
596                 }
597         else
598                 {
599                 rc_overlay_free(rc, od);
600                 }
601 }
602
603 static gboolean renderer_overlay_get(void *renderer, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
604 {
605         RendererClutter *rc = (RendererClutter *)renderer;
606
607         PixbufRenderer *pr = rc->pr;
608         OverlayData *od;
609
610         g_return_val_if_fail(IS_PIXBUF_RENDERER(pr), FALSE);
611
612         od = rc_overlay_find(rc, id);
613         if (!od) return FALSE;
614
615         if (pixbuf) *pixbuf = od->pixbuf;
616         if (x) *x = od->x;
617         if (y) *y = od->y;
618
619         return TRUE;
620 }
621
622
623 static void renderer_update_sizes(void *renderer)
624 {
625         RendererClutter *rc = (RendererClutter *)renderer;
626         ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; 
627
628         rc->stereo_off_x = 0;
629         rc->stereo_off_y = 0;
630         
631         if (rc->stereo_mode & PR_STEREO_RIGHT) 
632                 {
633                 if (rc->stereo_mode & PR_STEREO_HORIZ) 
634                         {
635                         rc->stereo_off_x = rc->pr->viewport_width;
636                         }
637                 else if (rc->stereo_mode & PR_STEREO_VERT) 
638                         {
639                         rc->stereo_off_y = rc->pr->viewport_height;
640                         }
641                 else if (rc->stereo_mode & PR_STEREO_FIXED) 
642                         {
643                         rc->stereo_off_x = rc->pr->stereo_fixed_x_right;
644                         rc->stereo_off_y = rc->pr->stereo_fixed_y_right;
645                         }
646                 }
647         else
648                 {
649                 if (rc->stereo_mode & PR_STEREO_FIXED) 
650                         {
651                         rc->stereo_off_x = rc->pr->stereo_fixed_x_left;
652                         rc->stereo_off_y = rc->pr->stereo_fixed_y_left;
653                         }
654                 }
655         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);
656
657         printf("renderer_update_sizes  scale %d %d\n", rc->pr->width, rc->pr->height);
658
659         clutter_stage_set_color(CLUTTER_STAGE(rc->stage), &stage_color);
660
661
662         clutter_actor_set_size(rc->group, rc->pr->viewport_width, rc->pr->viewport_height);
663         clutter_actor_set_position(rc->group, rc->stereo_off_x, rc->stereo_off_y);
664         
665         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->group),
666                                                 CLUTTER_Y_AXIS,
667                                                 (rc->stereo_mode & PR_STEREO_MIRROR) ? 180 : 0, 
668                                                 rc->pr->viewport_width / 2.0, 0, 0);
669
670         clutter_actor_set_rotation(CLUTTER_ACTOR(rc->group),
671                                                 CLUTTER_X_AXIS,
672                                                 (rc->stereo_mode & PR_STEREO_FLIP) ? 180 : 0,
673                                                 0, rc->pr->viewport_height / 2.0, 0);
674
675         rc_sync_actor(rc);
676         rc_overlay_update_positions(rc);
677 }
678
679 static void renderer_scroll(void *renderer, gint x_off, gint y_off)
680 {
681         printf("renderer_scroll\n");
682         RendererClutter *rc = (RendererClutter *)renderer;
683         PixbufRenderer *pr = rc->pr;
684
685         rc_sync_actor(rc);
686 }
687
688 static void renderer_stereo_set(void *renderer, gint stereo_mode)
689 {
690         RendererClutter *rc = (RendererClutter *)renderer;
691
692         rc->stereo_mode = stereo_mode;
693 }
694
695 static void renderer_free(void *renderer)
696 {
697         RendererClutter *rc = (RendererClutter *)renderer;
698         GtkWidget *widget = gtk_bin_get_child(GTK_BIN(rc->pr));
699
700         renderer_remove_pending_updates(rc);
701
702         rc_overlay_free_all(rc);
703         
704         if (widget)
705                 {
706                 /* widget still exists */
707                 clutter_actor_destroy(rc->group);
708                 if (clutter_group_get_n_children(CLUTTER_GROUP(rc->stage)) == 0)
709                         {
710                         printf("destroy %p\n", rc->widget);
711                         /* this was the last user */
712                         gtk_widget_destroy(rc->widget);
713                         }
714                 else
715                         {
716                         printf("keep %p\n", rc->widget);
717                         g_object_unref(G_OBJECT(rc->widget));
718                         }
719                 }
720         g_free(rc);
721 }
722
723 RendererFuncs *renderer_clutter_new(PixbufRenderer *pr)
724 {
725         RendererClutter *rc = g_new0(RendererClutter, 1);
726         
727         rc->pr = pr;
728         
729         rc->f.area_changed = renderer_area_changed;
730         rc->f.update_pixbuf = renderer_update_pixbuf;
731         rc->f.free = renderer_free;
732         rc->f.update_zoom = renderer_update_zoom;
733         rc->f.invalidate_region = renderer_invalidate_region;
734         rc->f.scroll = renderer_scroll;
735         rc->f.update_sizes = renderer_update_sizes;
736
737
738         rc->f.overlay_add = renderer_overlay_add;
739         rc->f.overlay_set = renderer_overlay_set;
740         rc->f.overlay_get = renderer_overlay_get;
741         rc->f.overlay_draw = renderer_overlay_draw;
742
743         rc->f.stereo_set = renderer_stereo_set;
744         
745         
746         rc->stereo_mode = 0;
747         rc->stereo_off_x = 0;
748         rc->stereo_off_y = 0;
749
750         rc->idle_update = 0;
751         rc->pending_updates = NULL;
752
753         rc->widget = gtk_bin_get_child(GTK_BIN(rc->pr));
754         
755         if (rc->widget)
756                 {
757                 if (!GTK_CLUTTER_IS_EMBED(rc->widget))
758                         {
759                         g_free(rc);
760                         DEBUG_0("pixbuf renderer has a child of other type than gtk_clutter_embed");
761                         return NULL;
762                         }
763                 }
764         else 
765                 {
766                 rc->widget = gtk_clutter_embed_new();
767                 gtk_container_add(GTK_CONTAINER(rc->pr), rc->widget);
768                 }
769                 
770         gtk_event_box_set_above_child (GTK_EVENT_BOX(rc->pr), TRUE);
771         rc->stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (rc->widget));
772         
773         rc->group = clutter_group_new();
774         clutter_container_add_actor(CLUTTER_CONTAINER(rc->stage), rc->group);
775         clutter_actor_set_clip_to_allocation(CLUTTER_ACTOR(rc->group), TRUE);
776   
777         rc->texture = clutter_texture_new ();
778         clutter_container_add_actor(CLUTTER_CONTAINER(rc->group), rc->texture);
779         rc_set_shader(clutter_texture_get_cogl_material(rc->texture));
780         g_object_ref(G_OBJECT(rc->widget));
781   
782         gtk_widget_show(rc->widget);
783         return (RendererFuncs *) rc;
784 }
785
786 #endif 
787 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */