Ejemplo n.º 1
0
int
cogl_texture_get_data (CoglHandle       handle,
		       CoglPixelFormat  format,
		       unsigned int     rowstride,
		       guint8          *data)
{
  CoglTexture     *tex;
  int              bpp;
  int              byte_size;
  CoglPixelFormat  closest_format;
  int              closest_bpp;
  GLenum           closest_gl_format;
  GLenum           closest_gl_type;
  CoglBitmap      *target_bmp;
  CoglBitmap      *new_bmp;
  guint8          *src;
  guint8          *dst;
  int              y;
  int              tex_width;
  int              tex_height;

  CoglTextureGetData tg_data;

  if (!cogl_is_texture (handle))
    return 0;

  tex = COGL_TEXTURE (handle);

  /* Default to internal format if none specified */
  if (format == COGL_PIXEL_FORMAT_ANY)
    format = cogl_texture_get_format (handle);

  tex_width = cogl_texture_get_width (handle);
  tex_height = cogl_texture_get_height (handle);

  /* Rowstride from texture width if none specified */
  bpp = _cogl_get_format_bpp (format);
  if (rowstride == 0)
    rowstride = tex_width * bpp;

  /* Return byte size if only that requested */
  byte_size = tex_height * rowstride;
  if (data == NULL)
    return byte_size;

  closest_format =
    _cogl_texture_driver_find_best_gl_get_data_format (format,
                                                       &closest_gl_format,
                                                       &closest_gl_type);
  closest_bpp = _cogl_get_format_bpp (closest_format);

  /* Is the requested format supported? */
  if (closest_format == format)
    /* Target user data directly */
    target_bmp = _cogl_bitmap_new_from_data (data,
                                             format,
                                             tex_width,
                                             tex_height,
                                             rowstride,
                                             NULL, NULL);
  else
    {
      int target_rowstride = tex_width * closest_bpp;
      guint8 *target_data = g_malloc (tex_height * target_rowstride);
      target_bmp = _cogl_bitmap_new_from_data (target_data,
                                               closest_format,
                                               tex_width,
                                               tex_height,
                                               target_rowstride,
                                               (CoglBitmapDestroyNotify) g_free,
                                               NULL);
    }

  tg_data.orig_width = tex_width;
  tg_data.orig_height = tex_height;
  tg_data.target_bmp = target_bmp;
  tg_data.target_bits = _cogl_bitmap_map (target_bmp, COGL_BUFFER_ACCESS_WRITE,
                                          COGL_BUFFER_MAP_HINT_DISCARD);
  if (tg_data.target_bits == NULL)
    {
      cogl_object_unref (target_bmp);
      return 0;
    }
  tg_data.success = TRUE;

  /* Iterating through the subtextures allows piecing together
   * the data for a sliced texture, and allows us to do the
   * read-from-framebuffer logic here in a simple fashion rather than
   * passing offsets down through the code. */
  _cogl_texture_foreach_sub_texture_in_region (handle,
                                               0, 0, 1, 1,
                                               texture_get_cb,
                                               &tg_data);

  _cogl_bitmap_unmap (target_bmp);

  /* XXX: In some cases _cogl_texture_2d_download_from_gl may fail
   * to read back the texture data; such as for GLES which doesn't
   * support glGetTexImage, so here we fallback to drawing the
   * texture and reading the pixels from the framebuffer. */
  if (!tg_data.success)
    _cogl_texture_draw_and_read (tex, target_bmp,
                                 closest_gl_format,
                                 closest_gl_type);

  /* Was intermediate used? */
  if (closest_format != format)
    {
      guint8 *new_bmp_data;
      int new_bmp_rowstride;

      /* Convert to requested format */
      new_bmp = _cogl_bitmap_convert_format_and_premult (target_bmp,
                                                         format);

      /* Free intermediate data and return if failed */
      cogl_object_unref (target_bmp);

      if (new_bmp == NULL)
        return 0;

      new_bmp_rowstride = _cogl_bitmap_get_rowstride (new_bmp);
      new_bmp_data = _cogl_bitmap_map (new_bmp, COGL_BUFFER_ACCESS_WRITE,
                                       COGL_BUFFER_MAP_HINT_DISCARD);

      if (new_bmp_data == NULL)
        {
          cogl_object_unref (new_bmp);
          return 0;
        }

      /* Copy to user buffer */
      for (y = 0; y < tex_height; ++y)
        {
          src = new_bmp_data + y * new_bmp_rowstride;
          dst = data + y * rowstride;
          memcpy (dst, src, tex_width * bpp);
        }

      _cogl_bitmap_unmap (new_bmp);

      /* Free converted data */
      cogl_object_unref (new_bmp);
    }

  return byte_size;
}
Ejemplo n.º 2
0
static int
_cogl_texture_2d_get_data (CoglTexture     *tex,
                           CoglPixelFormat  format,
                           unsigned int     rowstride,
                           guint8          *data)
{
  CoglTexture2D   *tex_2d = COGL_TEXTURE_2D (tex);
  int              bpp;
  int              byte_size;
  CoglPixelFormat  closest_format;
  int              closest_bpp;
  GLenum           closest_gl_format;
  GLenum           closest_gl_type;
  CoglBitmap       target_bmp;
  CoglBitmap       new_bmp;
  gboolean         success;
  guint8          *src;
  guint8          *dst;
  int              y;

  /* Default to internal format if none specified */
  if (format == COGL_PIXEL_FORMAT_ANY)
    format = tex_2d->format;

  /* Rowstride from texture width if none specified */
  bpp = _cogl_get_format_bpp (format);
  if (rowstride == 0)
    rowstride = tex_2d->width * bpp;

  /* Return byte size if only that requested */
  byte_size =  tex_2d->height * rowstride;
  if (data == NULL)
    return byte_size;

  closest_format =
    _cogl_texture_driver_find_best_gl_get_data_format (format,
                                                       &closest_gl_format,
                                                       &closest_gl_type);
  closest_bpp = _cogl_get_format_bpp (closest_format);

  target_bmp.width = tex_2d->width;
  target_bmp.height = tex_2d->height;

  /* Is the requested format supported? */
  if (closest_format == format)
    {
      /* Target user data directly */
      target_bmp.format = format;
      target_bmp.rowstride = rowstride;
      target_bmp.data = data;
    }
  else
    {
      /* Target intermediate buffer */
      target_bmp.format = closest_format;
      target_bmp.rowstride = target_bmp.width * closest_bpp;
      target_bmp.data = g_malloc (target_bmp.height * target_bmp.rowstride);
    }

  _cogl_texture_driver_prep_gl_for_pixels_download (target_bmp.rowstride,
                                                    closest_bpp);

  GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) );
  if (!_cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_2D,
                                              closest_gl_format,
                                              closest_gl_type,
                                              target_bmp.data))
    {
      /* XXX: In some cases _cogl_texture_2d_download_from_gl may
       * fail to read back the texture data; such as for GLES which doesn't
       * support glGetTexImage, so here we fallback to drawing the texture
       * and reading the pixels from the framebuffer. */
      _cogl_texture_draw_and_read (tex, &target_bmp,
                                   closest_gl_format,
                                   closest_gl_type);
    }

  /* Was intermediate used? */
  if (closest_format != format)
    {
      /* Convert to requested format */
      success = _cogl_bitmap_convert_format_and_premult (&target_bmp,
                                                         &new_bmp,
                                                         format);

      /* Free intermediate data and return if failed */
      g_free (target_bmp.data);
      if (!success)
        return 0;

      /* Copy to user buffer */
      for (y = 0; y < new_bmp.height; ++y)
        {
          src = new_bmp.data + y * new_bmp.rowstride;
          dst = data + y * rowstride;
          memcpy (dst, src, new_bmp.width);
        }

      /* Free converted data */
      g_free (new_bmp.data);
    }

  return byte_size;
}