Blame clutter/clutter-image.c

Packit 31ecd5
/*
Packit 31ecd5
 * Clutter.
Packit 31ecd5
 *
Packit 31ecd5
 * An OpenGL based 'interactive image' library.
Packit 31ecd5
 *
Packit 31ecd5
 * Copyright (C) 2012  Intel Corporation.
Packit 31ecd5
 *
Packit 31ecd5
 * This library is free software; you can redistribute it and/or
Packit 31ecd5
 * modify it under the terms of the GNU Lesser General Public
Packit 31ecd5
 * License as published by the Free Software Foundation; either
Packit 31ecd5
 * version 2 of the License, or (at your option) any later version.
Packit 31ecd5
 *
Packit 31ecd5
 * This library is distributed in the hope that it will be useful,
Packit 31ecd5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 31ecd5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 31ecd5
 * Lesser General Public License for more details.
Packit 31ecd5
 *
Packit 31ecd5
 * You should have received a copy of the GNU Lesser General Public
Packit 31ecd5
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Packit 31ecd5
 *
Packit 31ecd5
 * Author:
Packit 31ecd5
 *   Emmanuele Bassi <ebassi@linux.intel.com>
Packit 31ecd5
 */
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * SECTION:clutter-image
Packit 31ecd5
 * @Title: ClutterImage
Packit 31ecd5
 * @Short_Description: Image data content
Packit 31ecd5
 *
Packit 31ecd5
 * #ClutterImage is a #ClutterContent implementation that displays
Packit 31ecd5
 * image data inside a #ClutterActor.
Packit 31ecd5
 *
Packit 31ecd5
 * See [image.c](https://git.gnome.org/browse/clutter/tree/examples/image-content.c?h=clutter-1.18)
Packit 31ecd5
 * for an example of how to use #ClutterImage.
Packit 31ecd5
 *
Packit 31ecd5
 * #ClutterImage is available since Clutter 1.10.
Packit 31ecd5
 */
Packit 31ecd5
Packit 31ecd5
#ifdef HAVE_CONFIG_H
Packit 31ecd5
#include "config.h"
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
#define CLUTTER_ENABLE_EXPERIMENTAL_API
Packit 31ecd5
Packit 31ecd5
#include "clutter-image.h"
Packit 31ecd5
Packit 31ecd5
#include "clutter-actor-private.h"
Packit 31ecd5
#include "clutter-color.h"
Packit 31ecd5
#include "clutter-content-private.h"
Packit 31ecd5
#include "clutter-debug.h"
Packit 31ecd5
#include "clutter-paint-node.h"
Packit 31ecd5
#include "clutter-paint-nodes.h"
Packit 31ecd5
#include "clutter-private.h"
Packit 31ecd5
Packit 31ecd5
struct _ClutterImagePrivate
Packit 31ecd5
{
Packit 31ecd5
  CoglTexture *texture;
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
static void clutter_content_iface_init (ClutterContentIface *iface);
Packit 31ecd5
Packit 31ecd5
G_DEFINE_TYPE_WITH_CODE (ClutterImage, clutter_image, G_TYPE_OBJECT,
Packit 31ecd5
                         G_ADD_PRIVATE (ClutterImage)
Packit 31ecd5
                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
Packit 31ecd5
                                                clutter_content_iface_init))
Packit 31ecd5
Packit 31ecd5
GQuark
Packit 31ecd5
clutter_image_error_quark (void)
Packit 31ecd5
{
Packit 31ecd5
  return g_quark_from_static_string ("clutter-image-error-quark");
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_image_finalize (GObject *gobject)
Packit 31ecd5
{
Packit 31ecd5
  ClutterImagePrivate *priv = CLUTTER_IMAGE (gobject)->priv;
Packit 31ecd5
Packit 31ecd5
  if (priv->texture != NULL)
Packit 31ecd5
    {
Packit 31ecd5
      cogl_object_unref (priv->texture);
Packit 31ecd5
      priv->texture = NULL;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  G_OBJECT_CLASS (clutter_image_parent_class)->finalize (gobject);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_image_class_init (ClutterImageClass *klass)
Packit 31ecd5
{
Packit 31ecd5
  G_OBJECT_CLASS (klass)->finalize = clutter_image_finalize;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_image_init (ClutterImage *self)
Packit 31ecd5
{
Packit 31ecd5
  self->priv = clutter_image_get_instance_private (self);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_image_paint_content (ClutterContent   *content,
Packit 31ecd5
                             ClutterActor     *actor,
Packit 31ecd5
                             ClutterPaintNode *root)
Packit 31ecd5
{
Packit 31ecd5
  ClutterImagePrivate *priv = CLUTTER_IMAGE (content)->priv;
Packit 31ecd5
  ClutterPaintNode *node;
Packit 31ecd5
Packit 31ecd5
  if (priv->texture == NULL)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  node = clutter_actor_create_texture_paint_node (actor, priv->texture);
Packit 31ecd5
  clutter_paint_node_set_name (node, "Image Content");
Packit 31ecd5
  clutter_paint_node_add_child (root, node);
Packit 31ecd5
  clutter_paint_node_unref (node);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
clutter_image_get_preferred_size (ClutterContent *content,
Packit 31ecd5
                                  gfloat         *width,
Packit 31ecd5
                                  gfloat         *height)
Packit 31ecd5
{
Packit 31ecd5
  ClutterImagePrivate *priv = CLUTTER_IMAGE (content)->priv;
Packit 31ecd5
Packit 31ecd5
  if (priv->texture == NULL)
Packit 31ecd5
    return FALSE;
Packit 31ecd5
Packit 31ecd5
  if (width != NULL)
Packit 31ecd5
    *width = cogl_texture_get_width (priv->texture);
Packit 31ecd5
Packit 31ecd5
  if (height != NULL)
Packit 31ecd5
    *height = cogl_texture_get_height (priv->texture);
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_content_iface_init (ClutterContentIface *iface)
Packit 31ecd5
{
Packit 31ecd5
  iface->get_preferred_size = clutter_image_get_preferred_size;
Packit 31ecd5
  iface->paint_content = clutter_image_paint_content;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * clutter_image_new:
Packit 31ecd5
 *
Packit 31ecd5
 * Creates a new #ClutterImage instance.
Packit 31ecd5
 *
Packit 31ecd5
 * Return value: (transfer full): the newly created #ClutterImage instance.
Packit 31ecd5
 *   Use g_object_unref() when done.
Packit 31ecd5
 *
Packit 31ecd5
 * Since: 1.10
Packit 31ecd5
 */
Packit 31ecd5
ClutterContent *
Packit 31ecd5
clutter_image_new (void)
Packit 31ecd5
{
Packit 31ecd5
  return g_object_new (CLUTTER_TYPE_IMAGE, NULL);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * clutter_image_set_data:
Packit 31ecd5
 * @image: a #ClutterImage
Packit 31ecd5
 * @data: (array): the image data, as an array of bytes
Packit 31ecd5
 * @pixel_format: the Cogl pixel format of the image data
Packit 31ecd5
 * @width: the width of the image data
Packit 31ecd5
 * @height: the height of the image data
Packit 31ecd5
 * @row_stride: the length of each row inside @data
Packit 31ecd5
 * @error: return location for a #GError, or %NULL
Packit 31ecd5
 *
Packit 31ecd5
 * Sets the image data to be displayed by @image.
Packit 31ecd5
 *
Packit 31ecd5
 * If the image data was successfully loaded, the @image will be invalidated.
Packit 31ecd5
 *
Packit 31ecd5
 * In case of error, the @error value will be set, and this function will
Packit 31ecd5
 * return %FALSE.
Packit 31ecd5
 *
Packit 31ecd5
 * The image data is copied in texture memory.
Packit 31ecd5
 *
Packit 31ecd5
 * The image data is expected to be a linear array of RGBA or RGB pixel data;
Packit 31ecd5
 * how to retrieve that data is left to platform specific image loaders. For
Packit 31ecd5
 * instance, if you use the GdkPixbuf library:
Packit 31ecd5
 *
Packit 31ecd5
 * |[
Packit 31ecd5
 *   ClutterContent *image = clutter_image_new ();
Packit 31ecd5
 *
Packit 31ecd5
 *   GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
Packit 31ecd5
 *
Packit 31ecd5
 *   clutter_image_set_data (CLUTTER_IMAGE (image),
Packit 31ecd5
 *                           gdk_pixbuf_get_pixels (pixbuf),
Packit 31ecd5
 *                           gdk_pixbuf_get_has_alpha (pixbuf)
Packit 31ecd5
 *                             ? COGL_PIXEL_FORMAT_RGBA_8888
Packit 31ecd5
 *                             : COGL_PIXEL_FORMAT_RGB_888,
Packit 31ecd5
 *                           gdk_pixbuf_get_width (pixbuf),
Packit 31ecd5
 *                           gdk_pixbuf_get_height (pixbuf),
Packit 31ecd5
 *                           gdk_pixbuf_get_rowstride (pixbuf),
Packit 31ecd5
 *                           &error);
Packit 31ecd5
 *
Packit 31ecd5
 *   g_object_unref (pixbuf);
Packit 31ecd5
 * ]|
Packit 31ecd5
 *
Packit 31ecd5
 * Return value: %TRUE if the image data was successfully loaded,
Packit 31ecd5
 *   and %FALSE otherwise.
Packit 31ecd5
 *
Packit 31ecd5
 * Since: 1.10
Packit 31ecd5
 */
Packit 31ecd5
gboolean
Packit 31ecd5
clutter_image_set_data (ClutterImage     *image,
Packit 31ecd5
                        const guint8     *data,
Packit 31ecd5
                        CoglPixelFormat   pixel_format,
Packit 31ecd5
                        guint             width,
Packit 31ecd5
                        guint             height,
Packit 31ecd5
                        guint             row_stride,
Packit 31ecd5
                        GError          **error)
Packit 31ecd5
{
Packit 31ecd5
  ClutterImagePrivate *priv;
Packit 31ecd5
  CoglTextureFlags flags;
Packit 31ecd5
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
Packit 31ecd5
  g_return_val_if_fail (data != NULL, FALSE);
Packit 31ecd5
Packit 31ecd5
  priv = image->priv;
Packit 31ecd5
Packit 31ecd5
  if (priv->texture != NULL)
Packit 31ecd5
    cogl_object_unref (priv->texture);
Packit 31ecd5
Packit 31ecd5
  flags = COGL_TEXTURE_NONE;
Packit 31ecd5
  if (width >= 512 && height >= 512)
Packit 31ecd5
    flags |= COGL_TEXTURE_NO_ATLAS;
Packit 31ecd5
Packit 31ecd5
  priv->texture = cogl_texture_new_from_data (width, height,
Packit 31ecd5
                                              flags,
Packit 31ecd5
                                              pixel_format,
Packit 31ecd5
                                              COGL_PIXEL_FORMAT_ANY,
Packit 31ecd5
                                              row_stride,
Packit 31ecd5
                                              data);
Packit 31ecd5
  if (priv->texture == NULL)
Packit 31ecd5
    {
Packit 31ecd5
      g_set_error_literal (error, CLUTTER_IMAGE_ERROR,
Packit 31ecd5
                           CLUTTER_IMAGE_ERROR_INVALID_DATA,
Packit 31ecd5
                           _("Unable to load image data"));
Packit 31ecd5
      return FALSE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  clutter_content_invalidate (CLUTTER_CONTENT (image));
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * clutter_image_set_bytes:
Packit 31ecd5
 * @image: a #ClutterImage
Packit 31ecd5
 * @data: the image data, as a #GBytes
Packit 31ecd5
 * @pixel_format: the Cogl pixel format of the image data
Packit 31ecd5
 * @width: the width of the image data
Packit 31ecd5
 * @height: the height of the image data
Packit 31ecd5
 * @row_stride: the length of each row inside @data
Packit 31ecd5
 * @error: return location for a #GError, or %NULL
Packit 31ecd5
 *
Packit 31ecd5
 * Sets the image data stored inside a #GBytes to be displayed by @image.
Packit 31ecd5
 *
Packit 31ecd5
 * If the image data was successfully loaded, the @image will be invalidated.
Packit 31ecd5
 *
Packit 31ecd5
 * In case of error, the @error value will be set, and this function will
Packit 31ecd5
 * return %FALSE.
Packit 31ecd5
 *
Packit 31ecd5
 * The image data contained inside the #GBytes is copied in texture memory,
Packit 31ecd5
 * and no additional reference is acquired on the @data.
Packit 31ecd5
 *
Packit 31ecd5
 * Return value: %TRUE if the image data was successfully loaded,
Packit 31ecd5
 *   and %FALSE otherwise.
Packit 31ecd5
 *
Packit 31ecd5
 * Since: 1.12
Packit 31ecd5
 */
Packit 31ecd5
gboolean
Packit 31ecd5
clutter_image_set_bytes (ClutterImage     *image,
Packit 31ecd5
                         GBytes           *data,
Packit 31ecd5
                         CoglPixelFormat   pixel_format,
Packit 31ecd5
                         guint             width,
Packit 31ecd5
                         guint             height,
Packit 31ecd5
                         guint             row_stride,
Packit 31ecd5
                         GError          **error)
Packit 31ecd5
{
Packit 31ecd5
  ClutterImagePrivate *priv;
Packit 31ecd5
  CoglTextureFlags flags;
Packit 31ecd5
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
Packit 31ecd5
  g_return_val_if_fail (data != NULL, FALSE);
Packit 31ecd5
Packit 31ecd5
  priv = image->priv;
Packit 31ecd5
Packit 31ecd5
  if (priv->texture != NULL)
Packit 31ecd5
    cogl_object_unref (priv->texture);
Packit 31ecd5
Packit 31ecd5
  flags = COGL_TEXTURE_NONE;
Packit 31ecd5
  if (width >= 512 && height >= 512)
Packit 31ecd5
    flags |= COGL_TEXTURE_NO_ATLAS;
Packit 31ecd5
Packit 31ecd5
  priv->texture = cogl_texture_new_from_data (width, height,
Packit 31ecd5
                                              flags,
Packit 31ecd5
                                              pixel_format,
Packit 31ecd5
                                              COGL_PIXEL_FORMAT_ANY,
Packit 31ecd5
                                              row_stride,
Packit 31ecd5
                                              g_bytes_get_data (data, NULL));
Packit 31ecd5
  if (priv->texture == NULL)
Packit 31ecd5
    {
Packit 31ecd5
      g_set_error_literal (error, CLUTTER_IMAGE_ERROR,
Packit 31ecd5
                           CLUTTER_IMAGE_ERROR_INVALID_DATA,
Packit 31ecd5
                           _("Unable to load image data"));
Packit 31ecd5
      return FALSE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  clutter_content_invalidate (CLUTTER_CONTENT (image));
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * clutter_image_set_area:
Packit 31ecd5
 * @image: a #ClutterImage
Packit 31ecd5
 * @data: (array): the image data, as an array of bytes
Packit 31ecd5
 * @pixel_format: the Cogl pixel format of the image data
Packit 31ecd5
 * @rect: a rectangle indicating the area that should be set
Packit 31ecd5
 * @row_stride: the length of each row inside @data
Packit 31ecd5
 * @error: return location for a #GError, or %NULL
Packit 31ecd5
 *
Packit 31ecd5
 * Sets the image data to be display by @image, using @rect to indicate
Packit 31ecd5
 * the position and size of the image data to be set.
Packit 31ecd5
 *
Packit 31ecd5
 * If the @image does not have any image data set when this function is
Packit 31ecd5
 * called, a new texture will be created with the size of the width and
Packit 31ecd5
 * height of the rectangle, i.e. calling this function on a newly created
Packit 31ecd5
 * #ClutterImage will be the equivalent of calling clutter_image_set_data().
Packit 31ecd5
 *
Packit 31ecd5
 * If the image data was successfully loaded, the @image will be invalidated.
Packit 31ecd5
 *
Packit 31ecd5
 * In case of error, the @error value will be set, and this function will
Packit 31ecd5
 * return %FALSE.
Packit 31ecd5
 *
Packit 31ecd5
 * The image data is copied in texture memory.
Packit 31ecd5
 *
Packit 31ecd5
 * Return value: %TRUE if the image data was successfully loaded,
Packit 31ecd5
 *   and %FALSE otherwise.
Packit 31ecd5
 *
Packit 31ecd5
 * Since: 1.10
Packit 31ecd5
 */
Packit 31ecd5
gboolean
Packit 31ecd5
clutter_image_set_area (ClutterImage                 *image,
Packit 31ecd5
                        const guint8                 *data,
Packit 31ecd5
                        CoglPixelFormat               pixel_format,
Packit 31ecd5
                        const cairo_rectangle_int_t  *area,
Packit 31ecd5
                        guint                         row_stride,
Packit 31ecd5
                        GError                      **error)
Packit 31ecd5
{
Packit 31ecd5
  ClutterImagePrivate *priv;
Packit 31ecd5
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
Packit 31ecd5
  g_return_val_if_fail (data != NULL, FALSE);
Packit 31ecd5
  g_return_val_if_fail (area != NULL, FALSE);
Packit 31ecd5
Packit 31ecd5
  priv = image->priv;
Packit 31ecd5
Packit 31ecd5
  if (priv->texture == NULL)
Packit 31ecd5
    {
Packit 31ecd5
      CoglTextureFlags flags = COGL_TEXTURE_NONE;
Packit 31ecd5
Packit 31ecd5
      if (area->width >= 512 && area->height >= 512)
Packit 31ecd5
        flags |= COGL_TEXTURE_NO_ATLAS;
Packit 31ecd5
Packit 31ecd5
      priv->texture = cogl_texture_new_from_data (area->width,
Packit 31ecd5
                                                  area->height,
Packit 31ecd5
                                                  flags,
Packit 31ecd5
                                                  pixel_format,
Packit 31ecd5
                                                  COGL_PIXEL_FORMAT_ANY,
Packit 31ecd5
                                                  row_stride,
Packit 31ecd5
                                                  data);
Packit 31ecd5
    }
Packit 31ecd5
  else
Packit 31ecd5
    {
Packit 31ecd5
      gboolean res;
Packit 31ecd5
Packit 31ecd5
      res = cogl_texture_set_region (priv->texture,
Packit 31ecd5
                                     0, 0,
Packit 31ecd5
                                     area->x, area->y,
Packit 31ecd5
                                     area->width, area->height,
Packit 31ecd5
                                     area->width, area->height,
Packit 31ecd5
                                     pixel_format,
Packit 31ecd5
                                     row_stride,
Packit 31ecd5
                                     data);
Packit 31ecd5
Packit 31ecd5
      if (!res)
Packit 31ecd5
        {
Packit 31ecd5
          cogl_object_unref (priv->texture);
Packit 31ecd5
          priv->texture = NULL;
Packit 31ecd5
        }
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  if (priv->texture == NULL)
Packit 31ecd5
    {
Packit 31ecd5
      g_set_error_literal (error, CLUTTER_IMAGE_ERROR,
Packit 31ecd5
                           CLUTTER_IMAGE_ERROR_INVALID_DATA,
Packit 31ecd5
                           _("Unable to load image data"));
Packit 31ecd5
      return FALSE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  clutter_content_invalidate (CLUTTER_CONTENT (image));
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/**
Packit 31ecd5
 * clutter_image_get_texture:
Packit 31ecd5
 * @image: a #ClutterImage
Packit 31ecd5
 *
Packit 31ecd5
 * Retrieves a pointer to the Cogl texture used by @image.
Packit 31ecd5
 *
Packit 31ecd5
 * If you change the contents of the returned Cogl texture you will need
Packit 31ecd5
 * to manually invalidate the @image with clutter_content_invalidate()
Packit 31ecd5
 * in order to update the actors using @image as their content.
Packit 31ecd5
 *
Packit 31ecd5
 * Return value: (transfer none): a pointer to the Cogl texture, or %NULL
Packit 31ecd5
 *
Packit 31ecd5
 * Since: 1.10
Packit 31ecd5
 * Stability: unstable
Packit 31ecd5
 */
Packit 31ecd5
CoglTexture *
Packit 31ecd5
clutter_image_get_texture (ClutterImage *image)
Packit 31ecd5
{
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_IMAGE (image), NULL);
Packit 31ecd5
Packit 31ecd5
  return image->priv->texture;
Packit 31ecd5
}