Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-image.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive image' library.
5  *
6  * Copyright (C) 2012  Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  * Author:
22  *   Emmanuele Bassi <ebassi@linux.intel.com>
23  */
24
25 /**
26  * SECTION:clutter-image
27  * @Title: ClutterImage
28  * @Short_Description: Image data content
29  *
30  * #ClutterImage is a #ClutterContent implementation that displays
31  * image data.
32  *
33  * <informalexample><programlisting>
34  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/image-content.c">
35  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
36  * </xi:include>
37  * </programlisting></informalexample>
38  *
39  * #ClutterImage is available since Clutter 1.10.
40  */
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 #define CLUTTER_ENABLE_EXPERIMENTAL_API
47
48 #include "clutter-image.h"
49
50 #include "clutter-color.h"
51 #include "clutter-content-private.h"
52 #include "clutter-debug.h"
53 #include "clutter-paint-node.h"
54 #include "clutter-paint-nodes.h"
55 #include "clutter-private.h"
56
57 struct _ClutterImagePrivate
58 {
59   CoglTexture *texture;
60 };
61
62 static void clutter_content_iface_init (ClutterContentIface *iface);
63
64 G_DEFINE_TYPE_WITH_CODE (ClutterImage, clutter_image, G_TYPE_OBJECT,
65                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
66                                                 clutter_content_iface_init))
67
68 GQuark
69 clutter_image_error_quark (void)
70 {
71   return g_quark_from_static_string ("clutter-image-error-quark");
72 }
73
74 static void
75 clutter_image_finalize (GObject *gobject)
76 {
77   ClutterImagePrivate *priv = CLUTTER_IMAGE (gobject)->priv;
78
79   if (priv->texture != NULL)
80     {
81       cogl_object_unref (priv->texture);
82       priv->texture = NULL;
83     }
84
85   G_OBJECT_CLASS (clutter_image_parent_class)->finalize (gobject);
86 }
87
88 static void
89 clutter_image_class_init (ClutterImageClass *klass)
90 {
91   g_type_class_add_private (klass, sizeof (ClutterImagePrivate));
92
93   G_OBJECT_CLASS (klass)->finalize = clutter_image_finalize;
94 }
95
96 static void
97 clutter_image_init (ClutterImage *self)
98 {
99   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_IMAGE,
100                                             ClutterImagePrivate);
101 }
102
103 static void
104 clutter_image_paint_content (ClutterContent   *content,
105                              ClutterActor     *actor,
106                              ClutterPaintNode *root)
107 {
108   ClutterImagePrivate *priv = CLUTTER_IMAGE (content)->priv;
109   ClutterScalingFilter min_f, mag_f;
110   ClutterPaintNode *node;
111   ClutterActorBox box;
112   ClutterColor color;
113   guint8 paint_opacity;
114
115   if (priv->texture == NULL)
116     return;
117
118   clutter_actor_get_content_box (actor, &box);
119   paint_opacity = clutter_actor_get_paint_opacity (actor);
120   clutter_actor_get_content_scaling_filters (actor, &min_f, &mag_f);
121
122   color.red = paint_opacity;
123   color.green = paint_opacity;
124   color.blue = paint_opacity;
125   color.alpha = paint_opacity;
126
127   node = clutter_texture_node_new (priv->texture, &color, min_f, mag_f);
128   clutter_paint_node_set_name (node, "Image");
129   clutter_paint_node_add_rectangle (node, &box);
130   clutter_paint_node_add_child (root, node);
131   clutter_paint_node_unref (node);
132 }
133
134 static gboolean
135 clutter_image_get_preferred_size (ClutterContent *content,
136                                   gfloat         *width,
137                                   gfloat         *height)
138 {
139   ClutterImagePrivate *priv = CLUTTER_IMAGE (content)->priv;
140
141   if (priv->texture == NULL)
142     return FALSE;
143
144   if (width != NULL)
145     *width = cogl_texture_get_width (priv->texture);
146
147   if (height != NULL)
148     *height = cogl_texture_get_height (priv->texture);
149
150   return TRUE;
151 }
152
153 static void
154 clutter_content_iface_init (ClutterContentIface *iface)
155 {
156   iface->get_preferred_size = clutter_image_get_preferred_size;
157   iface->paint_content = clutter_image_paint_content;
158 }
159
160 /**
161  * clutter_image_new:
162  *
163  * Creates a new #ClutterImage instance.
164  *
165  * Return value: (transfer full): the newly created #ClutterImage instance.
166  *   Use g_object_unref() when done.
167  *
168  * Since: 1.10
169  */
170 ClutterContent *
171 clutter_image_new (void)
172 {
173   return g_object_new (CLUTTER_TYPE_IMAGE, NULL);
174 }
175
176 /**
177  * clutter_image_set_data:
178  * @image: a #ClutterImage
179  * @data: (array): the image data, as an array of bytes
180  * @pixel_format: the Cogl pixel format of the image data
181  * @width: the width of the image data
182  * @height: the height of the image data
183  * @row_stride: the length of each row inside @data
184  * @error: return location for a #GError, or %NULL
185  *
186  * Sets the image data to be displayed by @image.
187  *
188  * If the image data was successfully loaded, the @image will be invalidated.
189  *
190  * In case of error, the @error value will be set, and this function will
191  * return %FALSE.
192  *
193  * The image data is copied in texture memory.
194  *
195  * Return value: %TRUE if the image data was successfully loaded,
196  *   and %FALSE otherwise.
197  *
198  * Since: 1.10
199  */
200 gboolean
201 clutter_image_set_data (ClutterImage     *image,
202                         const guint8     *data,
203                         CoglPixelFormat   pixel_format,
204                         guint             width,
205                         guint             height,
206                         guint             row_stride,
207                         GError          **error)
208 {
209   ClutterImagePrivate *priv;
210
211   g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
212   g_return_val_if_fail (data != NULL, FALSE);
213
214   priv = image->priv;
215
216   if (priv->texture != NULL)
217     cogl_object_unref (priv->texture);
218
219   priv->texture = cogl_texture_new_from_data (width, height,
220                                               COGL_TEXTURE_NONE,
221                                               pixel_format,
222                                               COGL_PIXEL_FORMAT_ANY,
223                                               row_stride,
224                                               data);
225   if (priv->texture == NULL)
226     {
227       g_set_error_literal (error, CLUTTER_IMAGE_ERROR,
228                            CLUTTER_IMAGE_ERROR_INVALID_DATA,
229                            _("Unable to load image data"));
230       return FALSE;
231     }
232
233   clutter_content_invalidate (CLUTTER_CONTENT (image));
234
235   return TRUE;
236 }
237
238 /**
239  * clutter_image_set_bytes:
240  * @image: a #ClutterImage
241  * @data: the image data, as a #GBytes
242  * @pixel_format: the Cogl pixel format of the image data
243  * @width: the width of the image data
244  * @height: the height of the image data
245  * @row_stride: the length of each row inside @data
246  * @error: return location for a #GError, or %NULL
247  *
248  * Sets the image data stored inside a #GBytes to be displayed by @image.
249  *
250  * If the image data was successfully loaded, the @image will be invalidated.
251  *
252  * In case of error, the @error value will be set, and this function will
253  * return %FALSE.
254  *
255  * The image data contained inside the #GBytes is copied in texture memory,
256  * and no additional reference is acquired on the @data.
257  *
258  * Return value: %TRUE if the image data was successfully loaded,
259  *   and %FALSE otherwise.
260  *
261  * Since: 1.12
262  */
263 gboolean
264 clutter_image_set_bytes (ClutterImage     *image,
265                          GBytes           *data,
266                          CoglPixelFormat   pixel_format,
267                          guint             width,
268                          guint             height,
269                          guint             row_stride,
270                          GError          **error)
271 {
272   ClutterImagePrivate *priv;
273
274   g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
275   g_return_val_if_fail (data != NULL, FALSE);
276
277   priv = image->priv;
278
279   if (priv->texture != NULL)
280     cogl_object_unref (priv->texture);
281
282   priv->texture = cogl_texture_new_from_data (width, height,
283                                               COGL_TEXTURE_NONE,
284                                               pixel_format,
285                                               COGL_PIXEL_FORMAT_ANY,
286                                               row_stride,
287                                               g_bytes_get_data (data, NULL));
288   if (priv->texture == NULL)
289     {
290       g_set_error_literal (error, CLUTTER_IMAGE_ERROR,
291                            CLUTTER_IMAGE_ERROR_INVALID_DATA,
292                            _("Unable to load image data"));
293       return FALSE;
294     }
295
296   clutter_content_invalidate (CLUTTER_CONTENT (image));
297
298   return TRUE;
299 }
300
301 /**
302  * clutter_image_set_area:
303  * @image: a #ClutterImage
304  * @data: (array): the image data, as an array of bytes
305  * @pixel_format: the Cogl pixel format of the image data
306  * @rect: a rectangle indicating the area that should be set
307  * @row_stride: the length of each row inside @data
308  * @error: return location for a #GError, or %NULL
309  *
310  * Sets the image data to be display by @image, using @rect to indicate
311  * the position and size of the image data to be set.
312  *
313  * If the @image does not have any image data set when this function is
314  * called, a new texture will be created with the size of the width and
315  * height of the rectangle, i.e. calling this function on a newly created
316  * #ClutterImage will be the equivalent of calling clutter_image_set_data().
317  *
318  * If the image data was successfully loaded, the @image will be invalidated.
319  *
320  * In case of error, the @error value will be set, and this function will
321  * return %FALSE.
322  *
323  * The image data is copied in texture memory.
324  *
325  * Return value: %TRUE if the image data was successfully loaded,
326  *   and %FALSE otherwise.
327  *
328  * Since: 1.10
329  */
330 gboolean
331 clutter_image_set_area (ClutterImage                 *image,
332                         const guint8                 *data,
333                         CoglPixelFormat               pixel_format,
334                         const cairo_rectangle_int_t  *area,
335                         guint                         row_stride,
336                         GError                      **error)
337 {
338   ClutterImagePrivate *priv;
339
340   g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
341   g_return_val_if_fail (data != NULL, FALSE);
342   g_return_val_if_fail (area != NULL, FALSE);
343
344   priv = image->priv;
345
346   if (priv->texture == NULL)
347     {
348       priv->texture = cogl_texture_new_from_data (area->width,
349                                                   area->height,
350                                                   COGL_TEXTURE_NONE,
351                                                   pixel_format,
352                                                   COGL_PIXEL_FORMAT_ANY,
353                                                   row_stride,
354                                                   data);
355     }
356   else
357     {
358       gboolean res;
359
360       res = cogl_texture_set_region (priv->texture,
361                                      0, 0,
362                                      area->x, area->y,
363                                      area->width, area->height,
364                                      area->width, area->height,
365                                      pixel_format,
366                                      row_stride,
367                                      data);
368
369       if (!res)
370         {
371           cogl_object_unref (priv->texture);
372           priv->texture = NULL;
373         }
374     }
375
376   if (priv->texture == NULL)
377     {
378       g_set_error_literal (error, CLUTTER_IMAGE_ERROR,
379                            CLUTTER_IMAGE_ERROR_INVALID_DATA,
380                            _("Unable to load image data"));
381       return FALSE;
382     }
383
384   clutter_content_invalidate (CLUTTER_CONTENT (image));
385
386   return TRUE;
387 }
388
389 /**
390  * clutter_image_get_texture:
391  * @image: a #ClutterImage
392  *
393  * Retrieves a pointer to the Cogl texture used by @image.
394  *
395  * If you change the contents of the returned Cogl texture you will need
396  * to manually invalidate the @image with clutter_content_invalidate()
397  * in order to update the actors using @image as their content.
398  *
399  * Return value: (transfer none): a pointer to the Cogl texture, or %NULL
400  *
401  * Since: 1.10
402  * Stability: unstable
403  */
404 CoglTexture *
405 clutter_image_get_texture (ClutterImage *image)
406 {
407   g_return_val_if_fail (CLUTTER_IS_IMAGE (image), NULL);
408
409   return image->priv->texture;
410 }