1 #include <stdlib.h>
2 #include <clutter/clutter.h>
3 
4 /* pixels between the source and its reflection */
5 #define V_PADDING       4
6 
7 static void
_clone_paint_cb(ClutterActor * actor)8 _clone_paint_cb (ClutterActor *actor)
9 {
10   ClutterActor *source;
11   ClutterActorBox box;
12   CoglHandle material;
13   gfloat width, height;
14   guint8 opacity;
15   CoglColor color_1, color_2;
16   CoglTextureVertex vertices[4];
17 
18   /* if we don't have a source actor, don't paint */
19   source = clutter_clone_get_source (CLUTTER_CLONE (actor));
20   if (source == NULL)
21     goto out;
22 
23   /* if the source texture does not have any content, don't paint */
24   material = clutter_texture_get_cogl_material (CLUTTER_TEXTURE (source));
25   if (material == NULL)
26     goto out;
27 
28   /* get the size of the reflection */
29   clutter_actor_get_allocation_box (actor, &box);
30   clutter_actor_box_get_size (&box, &width, &height);
31 
32   /* get the composite opacity of the actor */
33   opacity = clutter_actor_get_paint_opacity (actor);
34 
35   /* figure out the two colors for the reflection: the first is
36    * full color and the second is the same, but at 0 opacity
37    */
38   cogl_color_init_from_4f (&color_1, 1.0, 1.0, 1.0, opacity / 255.);
39   cogl_color_premultiply (&color_1);
40   cogl_color_init_from_4f (&color_2, 1.0, 1.0, 1.0, 0.0);
41   cogl_color_premultiply (&color_2);
42 
43   /* now describe the four vertices of the quad; since it has
44    * to be a reflection, we need to invert it as well
45    */
46   vertices[0].x = 0; vertices[0].y = 0; vertices[0].z = 0;
47   vertices[0].tx = 0.0; vertices[0].ty = 1.0;
48   vertices[0].color = color_1;
49 
50   vertices[1].x = width; vertices[1].y = 0; vertices[1].z = 0;
51   vertices[1].tx = 1.0; vertices[1].ty = 1.0;
52   vertices[1].color = color_1;
53 
54   vertices[2].x = width; vertices[2].y = height; vertices[2].z = 0;
55   vertices[2].tx = 1.0; vertices[2].ty = 0.0;
56   vertices[2].color = color_2;
57 
58   vertices[3].x = 0; vertices[3].y = height; vertices[3].z = 0;
59   vertices[3].tx = 0.0; vertices[3].ty = 0.0;
60   vertices[3].color = color_2;
61 
62   /* paint the same texture but with a different geometry */
63   cogl_set_source (material);
64   cogl_polygon (vertices, 4, TRUE);
65 
66 out:
67   /* prevent the default clone handler from running */
68   g_signal_stop_emission_by_name (actor, "paint");
69 }
70 
71 int
main(int argc,char * argv[])72 main (int argc, char *argv[])
73 {
74   ClutterActor *stage;
75   ClutterActor *texture;
76   GError *error = NULL;
77   ClutterActor *clone;
78   gfloat y_offset;
79 
80   if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
81     return 1;
82 
83   stage = clutter_stage_new ();
84   clutter_stage_set_title (CLUTTER_STAGE (stage), "Reflection");
85   g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
86 
87   texture = clutter_texture_new ();
88   clutter_texture_set_from_file (CLUTTER_TEXTURE (texture),
89                                  "redhand.png",
90                                  &error);
91   clutter_actor_add_constraint (texture, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5));
92   clutter_actor_add_constraint (texture, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.2));
93 
94   y_offset = clutter_actor_get_height (texture) + V_PADDING;
95 
96   clone = clutter_clone_new (texture);
97   clutter_actor_add_constraint (clone, clutter_bind_constraint_new (texture, CLUTTER_BIND_X, 0.0));
98   clutter_actor_add_constraint (clone, clutter_bind_constraint_new (texture, CLUTTER_BIND_Y, y_offset));
99   g_signal_connect (clone,
100                     "paint",
101                     G_CALLBACK (_clone_paint_cb),
102                     NULL);
103 
104   clutter_container_add (CLUTTER_CONTAINER (stage), texture, clone, NULL);
105 
106   clutter_actor_show (stage);
107 
108   clutter_main ();
109 
110   return EXIT_SUCCESS;
111 }
112