Beispiel #1
0
CoglBitmap *
_cogl_bitmap_copy (CoglBitmap *src_bmp,
                   CoglError **error)
{
  CoglBitmap *dst_bmp;
  CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp);
  int width = cogl_bitmap_get_width (src_bmp);
  int height = cogl_bitmap_get_height (src_bmp);

  dst_bmp =
    _cogl_bitmap_new_with_malloc_buffer (src_bmp->context,
                                         width, height,
                                         src_format,
                                         error);
  if (!dst_bmp)
    return NULL;

  if (!_cogl_bitmap_copy_subregion (src_bmp,
                                    dst_bmp,
                                    0, 0, /* src_x/y */
                                    0, 0, /* dst_x/y */
                                    width, height,
                                    error))
    {
      cogl_object_unref (dst_bmp);
      return NULL;
    }

  return dst_bmp;
}
Beispiel #2
0
CoglTexture3D *
cogl_texture_3d_new_from_data (CoglContext *context,
                               int width,
                               int height,
                               int depth,
                               CoglPixelFormat format,
                               int rowstride,
                               int image_stride,
                               const uint8_t *data,
                               CoglError **error)
{
  CoglBitmap *bitmap;
  CoglTexture3D *ret;

  _COGL_RETURN_VAL_IF_FAIL (data, NULL);
  _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);

  /* Rowstride from width if not given */
  if (rowstride == 0)
    rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
  /* Image stride from height and rowstride if not given */
  if (image_stride == 0)
    image_stride = height * rowstride;

  if (image_stride < rowstride * height)
    return NULL;

  /* GL doesn't support uploading when the image_stride isn't a
     multiple of the rowstride. If this happens we'll just pack the
     image into a new bitmap. The documentation for this function
     recommends avoiding this situation. */
  if (image_stride % rowstride != 0)
    {
      uint8_t *bmp_data;
      int bmp_rowstride;
      int z, y;

      bitmap = _cogl_bitmap_new_with_malloc_buffer (context,
                                                    width,
                                                    depth * height,
                                                    format,
                                                    error);
      if (!bitmap)
        return NULL;

      bmp_data = _cogl_bitmap_map (bitmap,
                                   COGL_BUFFER_ACCESS_WRITE,
                                   COGL_BUFFER_MAP_HINT_DISCARD,
                                   error);

      if (bmp_data == NULL)
        {
          cogl_object_unref (bitmap);
          return NULL;
        }

      bmp_rowstride = cogl_bitmap_get_rowstride (bitmap);

      /* Copy all of the images in */
      for (z = 0; z < depth; z++)
        for (y = 0; y < height; y++)
          memcpy (bmp_data + (z * bmp_rowstride * height +
                              bmp_rowstride * y),
                  data + z * image_stride + rowstride * y,
                  bmp_rowstride);

      _cogl_bitmap_unmap (bitmap);
    }
  else
    bitmap = cogl_bitmap_new_for_data (context,
                                       width,
                                       image_stride / rowstride * depth,
                                       format,
                                       rowstride,
                                       (uint8_t *) data);

  ret = cogl_texture_3d_new_from_bitmap (bitmap,
                                         height,
                                         depth);

  cogl_object_unref (bitmap);

  if (ret &&
      !cogl_texture_allocate (COGL_TEXTURE (ret), error))
    {
      cogl_object_unref (ret);
      return NULL;
    }

  return ret;
}
static CoglBool
_cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
                                             CoglTexture *texture,
                                             CoglBool is_foreign,
                                             int src_x,
                                             int src_y,
                                             int dst_x,
                                             int dst_y,
                                             int width,
                                             int height,
                                             int level,
                                             CoglBitmap *source_bmp,
				             GLuint source_gl_format,
				             GLuint source_gl_type,
                                             CoglError **error)
{
  GLenum gl_target;
  GLuint gl_handle;
  uint8_t *data;
  CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
  CoglBitmap *slice_bmp;
  int rowstride;
  GLenum gl_error;
  CoglBool status = TRUE;
  CoglError *internal_error = NULL;
  int level_width;
  int level_height;

  cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);

  /* If we have the GL_EXT_unpack_subimage extension then we can
     upload from subregions directly. Otherwise we may need to copy
     the bitmap */
  if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE) &&
      (src_x != 0 || src_y != 0 ||
       width != cogl_bitmap_get_width (source_bmp) ||
       height != cogl_bitmap_get_height (source_bmp)))
    {
      slice_bmp =
        _cogl_bitmap_new_with_malloc_buffer (ctx,
                                             width, height,
                                             source_format,
                                             error);
      if (!slice_bmp)
        return FALSE;

      if (!_cogl_bitmap_copy_subregion (source_bmp,
                                        slice_bmp,
                                        src_x, src_y,
                                        0, 0, /* dst_x/y */
                                        width, height,
                                        error))
        {
          cogl_object_unref (slice_bmp);
          return FALSE;
        }

      src_x = src_y = 0;
    }
  else
    {
      slice_bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error);
      if (!slice_bmp)
        return FALSE;
    }

  rowstride = cogl_bitmap_get_rowstride (slice_bmp);

  /* Setup gl alignment to match rowstride and top-left corner */
  prep_gl_for_pixels_upload_full (ctx, rowstride, src_x, src_y, bpp);

  data = _cogl_bitmap_gl_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error);

  /* NB: _cogl_bitmap_gl_bind() may return NULL when successfull so we
   * have to explicitly check the cogl error pointer to catch
   * problems... */
  if (internal_error)
    {
      _cogl_propagate_error (error, internal_error);
      cogl_object_unref (slice_bmp);
      return FALSE;
    }

  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

  /* Clear any GL errors */
  while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
    ;

  _cogl_texture_get_level_size (texture,
                                level,
                                &level_width,
                                &level_height,
                                NULL);

  if (level_width == width && level_height == height)
    {
      /* GL gets upset if you use glTexSubImage2D to define the
       * contents of a mipmap level so we make sure to use
       * glTexImage2D if we are uploading a full mipmap level.
       */
      ctx->glTexImage2D (gl_target,
                         level,
                         _cogl_texture_gl_get_format (texture),
                         width,
                         height,
                         0,
                         source_gl_format,
                         source_gl_type,
                         data);
    }
  else
    {
      /* GL gets upset if you use glTexSubImage2D to initialize the
       * contents of a mipmap level so if this is the first time
       * we've seen a request to upload to this level we call
       * glTexImage2D first to assert that the storage for this
       * level exists.
       */
      if (texture->max_level < level)
        {
          ctx->glTexImage2D (gl_target,
                             level,
                             _cogl_texture_gl_get_format (texture),
                             level_width,
                             level_height,
                             0,
                             source_gl_format,
                             source_gl_type,
                             NULL);
        }

      ctx->glTexSubImage2D (gl_target,
                            level,
                            dst_x, dst_y,
                            width, height,
                            source_gl_format,
                            source_gl_type,
                            data);
    }

  if (_cogl_gl_util_catch_out_of_memory (ctx, error))
    status = FALSE;

  _cogl_bitmap_gl_unbind (slice_bmp);

  cogl_object_unref (slice_bmp);

  return status;
}
static CoglBool
_cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
                                      GLenum gl_target,
                                      GLuint gl_handle,
                                      CoglBool is_foreign,
                                      GLint height,
                                      GLint depth,
                                      CoglBitmap *source_bmp,
                                      GLint internal_gl_format,
                                      GLuint source_gl_format,
                                      GLuint source_gl_type,
                                      CoglError **error)
{
  CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
  int rowstride = cogl_bitmap_get_rowstride (source_bmp);
  int bmp_width = cogl_bitmap_get_width (source_bmp);
  int bmp_height = cogl_bitmap_get_height (source_bmp);
  uint8_t *data;
  GLenum gl_error;

  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

  /* If the rowstride or image height can't be specified with just
     GL_ALIGNMENT alone then we need to copy the bitmap because there
     is no GL_ROW_LENGTH */
  if (rowstride / bpp != bmp_width ||
      height != bmp_height / depth)
    {
      CoglBitmap *bmp;
      int image_height = bmp_height / depth;
      CoglPixelFormat source_bmp_format = cogl_bitmap_get_format (source_bmp);
      int i;

      _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, bmp_width * bpp, bpp);

      /* Initialize the texture with empty data and then upload each
         image with a sub-region update */

      /* Clear any GL errors */
      while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
        ;

      ctx->glTexImage3D (gl_target,
                         0, /* level */
                         internal_gl_format,
                         bmp_width,
                         height,
                         depth,
                         0,
                         source_gl_format,
                         source_gl_type,
                         NULL);

      if (_cogl_gl_util_catch_out_of_memory (ctx, error))
        return FALSE;

      bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
                                                 bmp_width,
                                                 height,
                                                 source_bmp_format,
                                                 error);
      if (!bmp)
        return FALSE;

      for (i = 0; i < depth; i++)
        {
          if (!_cogl_bitmap_copy_subregion (source_bmp,
                                            bmp,
                                            0, image_height * i,
                                            0, 0,
                                            bmp_width,
                                            height,
                                            error))
            {
              cogl_object_unref (bmp);
              return FALSE;
            }

          data = _cogl_bitmap_gl_bind (bmp,
                                       COGL_BUFFER_ACCESS_READ, 0, error);
          if (!data)
            {
              cogl_object_unref (bmp);
              return FALSE;
            }

          /* Clear any GL errors */
          while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
            ;

          ctx->glTexSubImage3D (gl_target,
                                0, /* level */
                                0, /* xoffset */
                                0, /* yoffset */
                                i, /* zoffset */
                                bmp_width, /* width */
                                height, /* height */
                                1, /* depth */
                                source_gl_format,
                                source_gl_type,
                                data);

          if (_cogl_gl_util_catch_out_of_memory (ctx, error))
            {
              cogl_object_unref (bmp);
              _cogl_bitmap_gl_unbind (bmp);
              return FALSE;
            }

          _cogl_bitmap_gl_unbind (bmp);
        }

      cogl_object_unref (bmp);
    }
  else
    {
      data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error);
      if (!data)
        return FALSE;

      _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp);

      /* Clear any GL errors */
      while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
        ;

      ctx->glTexImage3D (gl_target,
                         0, /* level */
                         internal_gl_format,
                         bmp_width,
                         height,
                         depth,
                         0,
                         source_gl_format,
                         source_gl_type,
                         data);

      if (_cogl_gl_util_catch_out_of_memory (ctx, error))
        {
          _cogl_bitmap_gl_unbind (source_bmp);
          return FALSE;
        }

      _cogl_bitmap_gl_unbind (source_bmp);
    }

  return TRUE;
}
Beispiel #5
0
/* the error does not contain the filename as the caller already has it */
CoglBitmap *
_cogl_bitmap_from_file (const char  *filename,
			GError     **error)
{
  CFURLRef url;
  CGImageSourceRef image_source;
  CGImageRef image;
  int save_errno;
  CFStringRef type;
  size_t width, height, rowstride;
  uint8_t *out_data;
  CGColorSpaceRef color_space;
  CGContextRef bitmap_context;
  CoglBitmap *bmp;

  _COGL_GET_CONTEXT (ctx, NULL);

  g_assert (filename != NULL);
  g_assert (error == NULL || *error == NULL);

  url = CFURLCreateFromFileSystemRepresentation (NULL,
                                                 (guchar *) filename,
                                                 strlen (filename),
                                                 false);
  image_source = CGImageSourceCreateWithURL (url, NULL);
  save_errno = errno;
  CFRelease (url);

  if (image_source == NULL)
    {
      /* doesn't exist, not readable, etc. */
      g_set_error_literal (error,
                           COGL_BITMAP_ERROR,
                           COGL_BITMAP_ERROR_FAILED,
                           g_strerror (save_errno));
      return NULL;
    }

  /* Unknown images would be cleanly caught as zero width/height below, but try
   * to provide better error message
   */
  type = CGImageSourceGetType (image_source);
  if (type == NULL)
    {
      CFRelease (image_source);
      g_set_error_literal (error,
                           COGL_BITMAP_ERROR,
                           COGL_BITMAP_ERROR_UNKNOWN_TYPE,
                           "Unknown image type");
      return NULL;
    }

  CFRelease (type);

  image = CGImageSourceCreateImageAtIndex (image_source, 0, NULL);
  CFRelease (image_source);

  width = CGImageGetWidth (image);
  height = CGImageGetHeight (image);
  if (width == 0 || height == 0)
    {
      /* incomplete or corrupt */
      CFRelease (image);
      g_set_error_literal (error,
                           COGL_BITMAP_ERROR,
                           COGL_BITMAP_ERROR_CORRUPT_IMAGE,
                           "Image has zero width or height");
      return NULL;
    }

  /* allocate buffer big enough to hold pixel data */
  bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
                                             width, height,
                                             COGL_PIXEL_FORMAT_ARGB_8888);
  rowstride = cogl_bitmap_get_rowstride (bmp);
  out_data = _cogl_bitmap_map (bmp,
                               COGL_BUFFER_ACCESS_WRITE,
                               COGL_BUFFER_MAP_HINT_DISCARD);

  /* render to buffer */
  color_space = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
  bitmap_context = CGBitmapContextCreate (out_data,
                                          width, height, 8,
                                          rowstride, color_space,
                                          kCGImageAlphaPremultipliedFirst);
  CGColorSpaceRelease (color_space);

  {
    const CGRect rect = {{0, 0}, {width, height}};

    CGContextDrawImage (bitmap_context, rect, image);
  }

  CGImageRelease (image);
  CGContextRelease (bitmap_context);

  _cogl_bitmap_unmap (bmp);

  /* store bitmap info */
  return bmp;
}