static gboolean _cogl_blit_framebuffer_begin (CoglBlitData *data) { CoglHandle dst_fbo, src_fbo; gboolean ret; _COGL_GET_CONTEXT (ctx, FALSE); /* We can only blit between FBOs if both textures are the same format and the blit framebuffer extension is supported */ if ((cogl_texture_get_format (data->src_tex) & ~COGL_A_BIT) != (cogl_texture_get_format (data->dst_tex) & ~COGL_A_BIT) || !(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT)) return FALSE; dst_fbo = _cogl_offscreen_new_to_texture_full (data->dst_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); if (dst_fbo == COGL_INVALID_HANDLE) ret = FALSE; else { if (!cogl_framebuffer_allocate (dst_fbo, NULL)) ret = FALSE; else { src_fbo = _cogl_offscreen_new_to_texture_full (data->src_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */); if (src_fbo == COGL_INVALID_HANDLE) ret = FALSE; else { if (!cogl_framebuffer_allocate (src_fbo, NULL)) ret = FALSE; else _cogl_push_framebuffers (dst_fbo, src_fbo); cogl_handle_unref (src_fbo); } } cogl_handle_unref (dst_fbo); } return ret; }
static VALUE rb_cogl_texture_get_format (VALUE self) { CoglHandle tex = rb_cogl_texture_get_handle (self); return UINT2NUM (cogl_texture_get_format (tex)); }
CoglPipeline * _cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache, CoglHandle texture) { CoglPangoPipelineCacheEntry *entry; PipelineDestroyNotifyData *destroy_data; static CoglUserDataKey pipeline_destroy_notify_key; /* Look for an existing entry */ entry = g_hash_table_lookup (cache->hash_table, texture); if (entry) return cogl_object_ref (entry->pipeline); /* No existing pipeline was found so let's create another */ entry = g_slice_new (CoglPangoPipelineCacheEntry); if (texture) { CoglPipeline *base; entry->texture = cogl_object_ref (texture); if (cogl_texture_get_format (entry->texture) == COGL_PIXEL_FORMAT_A_8) base = get_base_texture_alpha_pipeline (cache); else base = get_base_texture_rgba_pipeline (cache); entry->pipeline = cogl_pipeline_copy (base); cogl_pipeline_set_layer_texture (entry->pipeline, 0 /* layer */, texture); } else { entry->texture = NULL; entry->pipeline = cogl_pipeline_new (); } /* Add a weak reference to the pipeline so we can remove it from the hash table when it is destroyed */ destroy_data = g_slice_new (PipelineDestroyNotifyData); destroy_data->cache = cache; destroy_data->texture = texture; cogl_object_set_user_data (entry->pipeline, &pipeline_destroy_notify_key, destroy_data, pipeline_destroy_notify_cb); g_hash_table_insert (cache->hash_table, texture ? cogl_object_ref (texture) : NULL, entry); /* This doesn't take a reference on the pipeline so that it will use the newly created reference */ return entry->pipeline; }
static CoglPixelFormat _cogl_texture_pixmap_x11_get_format (CoglTexture *tex) { CoglTexturePixmapX11 *tex_pixmap = COGL_TEXTURE_PIXMAP_X11 (tex); CoglHandle child_tex; child_tex = _cogl_texture_pixmap_x11_get_texture (tex_pixmap); /* Forward on to the child texture */ return cogl_texture_get_format (child_tex); }
static gboolean _cogl_blit_get_tex_data_begin (CoglBlitData *data) { data->format = cogl_texture_get_format (data->src_tex); data->bpp = _cogl_get_format_bpp (data->format); data->image_data = g_malloc (data->bpp * data->src_width * data->src_height); cogl_texture_get_data (data->src_tex, data->format, data->src_width * data->bpp, data->image_data); return TRUE; }
unsigned int cogl_texture_get_rowstride (CoglHandle handle) { CoglTexture *tex; if (!cogl_is_texture (handle)) return 0; /* FIXME: This function should go away. It previously just returned the rowstride that was used to upload the data as far as I can tell. This is not helpful */ tex = COGL_TEXTURE (handle); /* Just guess at a suitable rowstride */ return (_cogl_get_format_bpp (cogl_texture_get_format (tex)) * cogl_texture_get_width (tex)); }
gboolean _cogl_texture_set_region_from_bitmap (CoglHandle handle, int src_x, int src_y, int dst_x, int dst_y, unsigned int dst_width, unsigned int dst_height, CoglBitmap *bmp) { CoglTexture *tex = COGL_TEXTURE (handle); GLenum closest_gl_format; GLenum closest_gl_type; gboolean ret; /* Shortcut out early if the image is empty */ if (dst_width == 0 || dst_height == 0) return TRUE; /* Prepare the bitmap so that it will do the premultiplication conversion */ bmp = _cogl_texture_prepare_for_upload (bmp, cogl_texture_get_format (handle), NULL, NULL, &closest_gl_format, &closest_gl_type); ret = tex->vtable->set_region (handle, src_x, src_y, dst_x, dst_y, dst_width, dst_height, bmp); cogl_object_unref (bmp); return ret; }
static VALUE rb_cogl_texture_get_data (int argc, VALUE *argv, VALUE self) { CoglHandle tex = rb_cogl_texture_get_handle (self); VALUE format_arg, rowstride_arg; CoglPixelFormat format; guint rowstride; VALUE data; rb_scan_args (argc, argv, "02", &format_arg, &rowstride_arg); format = NIL_P (format_arg) ? cogl_texture_get_format (tex) : NUM2UINT (format_arg); rowstride = (NIL_P (rowstride_arg) || NUM2UINT (rowstride_arg) == 0) ? cogl_texture_get_rowstride (tex) : NUM2UINT (rowstride_arg); data = rb_str_buf_new (rowstride * cogl_texture_get_height (tex)); cogl_texture_get_data (tex, format, rowstride, (guchar *) RSTRING (data)->ptr); RSTRING (data)->len = rowstride * cogl_texture_get_height (tex); return data; }
int main (int argc, char *argv[]) { ClutterActor *video; GdkPixbuf *shot = NULL; gint duration; CoglHandle tex_id; CoglPixelFormat format; gint size; gint width; gint height; gint rowstride; guchar *data = NULL; #ifdef USE_HELIX clutter_helix_init (&argc, &argv); #else gst_init (&argc, &argv); #endif clutter_init (&argc, &argv); if (argc < 3) { g_print ("Usage: %s <path to movie file> <output png>\n", argv[0]); exit(-1); } totem_resources_monitor_start (argv[1], 60 * G_USEC_PER_SEC); #ifdef USE_HELIX video = clutter_helix_video_texture_new (); #else video = clutter_gst_video_texture_new (); #endif if (argv[1][0] == '/') clutter_media_set_filename(CLUTTER_MEDIA(video), argv[1]); else clutter_media_set_uri(CLUTTER_MEDIA(video), argv[1]); clutter_media_set_volume (CLUTTER_MEDIA(video), 0); clutter_media_set_playing (CLUTTER_MEDIA(video), TRUE); do { while (g_main_context_pending (NULL)) g_main_context_iteration (NULL, FALSE); duration = clutter_media_get_duration (CLUTTER_MEDIA(video)); } while (duration == 0); clutter_actor_realize (video); clutter_media_set_position (CLUTTER_MEDIA(video), duration/3); do { while (g_main_context_pending (NULL)) g_main_context_iteration (NULL, FALSE); } while (clutter_media_get_position (CLUTTER_MEDIA(video)) <= duration/3); tex_id = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (video)); if (tex_id) { format = cogl_texture_get_format (tex_id); size = cogl_texture_get_data (tex_id, format, 0, NULL); width = cogl_texture_get_width (tex_id); height = cogl_texture_get_height (tex_id); rowstride = cogl_texture_get_rowstride (tex_id); data = (guchar*) g_malloc (sizeof(guchar) * size); if (!data) g_error ("malloc");; cogl_texture_get_data (tex_id, format, rowstride, data); shot = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, FALSE, 8, width, height, rowstride, NULL, NULL); } totem_resources_monitor_stop (); if (shot) { GdkPixbuf *thumb, *pic; gint x, y, nw, nh, w, h, size; size = 128; /* FIXME swap RGB pixels */ w = clutter_actor_get_width (video); h = clutter_actor_get_height (video); nh = ( h * size) / w; if (nh <= size) { nw = size; x = 0; y = (size - nh) / 2; } else { nw = ( w * size ) / h; nh = size; x = (size - nw) / 2; y = 0; } thumb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size); gdk_pixbuf_fill (thumb, 0x000000FF); pic = gdk_pixbuf_scale_simple (shot, nw, nh, GDK_INTERP_BILINEAR); gdk_pixbuf_copy_area (pic, 0, 0, nw, nh, thumb, x, y); if (!gdk_pixbuf_save (thumb, argv[2], "png", NULL, NULL)) { g_error ("%s: Pixbuf save failed\n", argv[0]); exit(-1); } g_object_unref (shot); g_object_unref (thumb); g_object_unref (pic); exit(0); } exit (-1); }
CoglTexture * rut_gaussian_blurrer_blur (RutGaussianBlurrer *blurrer, CoglTexture *source) { unsigned int src_w, src_h; CoglPixelFormat format; CoglOffscreen *offscreen; /* create the first FBO to render the x pass */ src_w = cogl_texture_get_width (source); src_h = cogl_texture_get_height (source); format = cogl_texture_get_format (source); if (blurrer->width != src_w || blurrer->height != src_h || blurrer->format != format) { _rut_gaussian_blurrer_free_buffers (blurrer); } if (!blurrer->x_pass) { CoglError *error = NULL; CoglTexture2D *texture_2d = cogl_texture_2d_new_with_size (blurrer->ctx->cogl_context, src_w, src_h, format); if (error) { g_warning ("blurrer: could not create x pass texture: %s", error->message); } blurrer->x_pass = COGL_TEXTURE (texture_2d); blurrer->width = src_w; blurrer->height = src_h; blurrer->format = format; offscreen = cogl_offscreen_new_to_texture (blurrer->x_pass); blurrer->x_pass_fb = COGL_FRAMEBUFFER (offscreen); cogl_framebuffer_orthographic (blurrer->x_pass_fb, 0, 0, src_w, src_h, -1, 100); } if (!blurrer->y_pass) { /* create the second FBO (final destination) to render the y pass */ CoglTexture2D *texture_2d = cogl_texture_2d_new_with_size (blurrer->ctx->cogl_context, src_w, src_h, format); blurrer->destination = COGL_TEXTURE (texture_2d); blurrer->y_pass = blurrer->destination; offscreen = cogl_offscreen_new_to_texture (blurrer->destination); blurrer->y_pass_fb = COGL_FRAMEBUFFER (offscreen); cogl_framebuffer_orthographic (blurrer->y_pass_fb, 0, 0, src_w, src_h, -1, 100); } set_blurrer_pipeline_texture (blurrer->x_pass_pipeline, source, 1.0f / src_w, 0); set_blurrer_pipeline_texture (blurrer->y_pass_pipeline, blurrer->x_pass, 0, 1.0f / src_h); /* x pass */ cogl_framebuffer_draw_rectangle (blurrer->x_pass_fb, blurrer->x_pass_pipeline, 0, 0, blurrer->width, blurrer->height); /* y pass */ cogl_framebuffer_draw_rectangle (blurrer->y_pass_fb, blurrer->y_pass_pipeline, 0, 0, blurrer->width, blurrer->height); return cogl_object_ref (blurrer->destination); }
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; }
/* Reads back the contents of a texture by rendering it to the framebuffer * and reading back the resulting pixels. * * NB: Normally this approach isn't normally used since we can just use * glGetTexImage, but may be used as a fallback in some circumstances. */ gboolean _cogl_texture_draw_and_read (CoglHandle handle, CoglBitmap *target_bmp, GLuint target_gl_format, GLuint target_gl_type) { int bpp; CoglFramebuffer *framebuffer; int viewport[4]; CoglBitmap *alpha_bmp; CoglMatrixStack *projection_stack; CoglMatrixStack *modelview_stack; int target_width = _cogl_bitmap_get_width (target_bmp); int target_height = _cogl_bitmap_get_height (target_bmp); int target_rowstride = _cogl_bitmap_get_rowstride (target_bmp); _COGL_GET_CONTEXT (ctx, FALSE); bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); framebuffer = _cogl_get_draw_buffer (); /* Viewport needs to have some size and be inside the window for this */ _cogl_framebuffer_get_viewport4fv (framebuffer, viewport); if (viewport[0] < 0 || viewport[1] < 0 || viewport[2] <= 0 || viewport[3] <= 0) return FALSE; /* Setup orthographic projection into current viewport (0,0 in top-left * corner to draw the texture upside-down so we match the way cogl_read_pixels * works) */ projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); _cogl_matrix_stack_push (projection_stack); _cogl_matrix_stack_load_identity (projection_stack); _cogl_matrix_stack_ortho (projection_stack, 0, (float)(viewport[2]), (float)(viewport[3]), 0, (float)(0), (float)(100)); modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer); _cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack); /* Direct copy operation */ if (ctx->texture_download_pipeline == COGL_INVALID_HANDLE) { ctx->texture_download_pipeline = cogl_pipeline_new (); cogl_pipeline_set_blend (ctx->texture_download_pipeline, "RGBA = ADD (SRC_COLOR, 0)", NULL); } cogl_push_source (ctx->texture_download_pipeline); cogl_pipeline_set_layer_texture (ctx->texture_download_pipeline, 0, handle); cogl_pipeline_set_layer_combine (ctx->texture_download_pipeline, 0, /* layer */ "RGBA = REPLACE (TEXTURE)", NULL); cogl_pipeline_set_layer_filters (ctx->texture_download_pipeline, 0, COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST); do_texture_draw_and_read (handle, target_bmp, viewport); /* Check whether texture has alpha and framebuffer not */ /* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer still doesn't seem to have an alpha buffer. This might be just a PowerVR issue. GLint r_bits, g_bits, b_bits, a_bits; GE( glGetIntegerv (GL_ALPHA_BITS, &a_bits) ); GE( glGetIntegerv (GL_RED_BITS, &r_bits) ); GE( glGetIntegerv (GL_GREEN_BITS, &g_bits) ); GE( glGetIntegerv (GL_BLUE_BITS, &b_bits) ); printf ("R bits: %d\n", r_bits); printf ("G bits: %d\n", g_bits); printf ("B bits: %d\n", b_bits); printf ("A bits: %d\n", a_bits); */ if ((cogl_texture_get_format (handle) & COGL_A_BIT)/* && a_bits == 0*/) { guint8 *srcdata; guint8 *dstdata; guint8 *srcpixel; guint8 *dstpixel; int x,y; int alpha_rowstride = bpp * target_width; if ((dstdata = _cogl_bitmap_map (target_bmp, COGL_BUFFER_ACCESS_WRITE, COGL_BUFFER_MAP_HINT_DISCARD)) == NULL) return FALSE; srcdata = g_malloc (alpha_rowstride * target_height); /* Create temp bitmap for alpha values */ alpha_bmp = _cogl_bitmap_new_from_data (srcdata, COGL_PIXEL_FORMAT_RGBA_8888, target_width, target_height, alpha_rowstride, (CoglBitmapDestroyNotify) g_free, NULL); /* Draw alpha values into RGB channels */ cogl_pipeline_set_layer_combine (ctx->texture_download_pipeline, 0, /* layer */ "RGBA = REPLACE (TEXTURE[A])", NULL); do_texture_draw_and_read (handle, alpha_bmp, viewport); /* Copy temp R to target A */ for (y=0; y<target_height; ++y) { for (x=0; x<target_width; ++x) { srcpixel = srcdata + x*bpp; dstpixel = dstdata + x*bpp; dstpixel[3] = srcpixel[0]; } srcdata += alpha_rowstride; dstdata += target_rowstride; } _cogl_bitmap_unmap (target_bmp); cogl_object_unref (alpha_bmp); } /* Restore old state */ _cogl_matrix_stack_pop (modelview_stack); _cogl_matrix_stack_pop (projection_stack); /* restore the original pipeline */ cogl_pop_source (); return TRUE; }
static void test_coglbox_init (TestCoglbox *self) { TestCoglboxPrivate *priv; guint width; guint height; guint rowstride; CoglPixelFormat format; gint size; guchar *data; gint x,y,t; guchar *pixel; self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self); /* Load image from file */ priv->cogl_tex_id[0] = cogl_texture_new_from_file ("redhand.png", 40, FALSE, COGL_PIXEL_FORMAT_ANY, NULL); if (priv->cogl_tex_id[0] == COGL_INVALID_HANDLE) { printf ("Failed loading redhand.png image!\n"); return; } printf("Texture loaded from file.\n"); /* Obtain pixel data */ format = cogl_texture_get_format (priv->cogl_tex_id[0]); g_assert(format == COGL_PIXEL_FORMAT_RGBA_8888 || format == COGL_PIXEL_FORMAT_ARGB_8888); width = cogl_texture_get_width (priv->cogl_tex_id[0]); height = cogl_texture_get_height (priv->cogl_tex_id[0]); size = cogl_texture_get_data (priv->cogl_tex_id[0], format, 0, NULL); printf("size: %dx%d\n", width, height); printf("format: 0x%x\n", format); printf("bytesize: %d\n", size); data = (guchar*) g_malloc (sizeof(guchar) * size); cogl_texture_get_data (priv->cogl_tex_id[0], format, 0, data); rowstride = cogl_texture_get_rowstride (priv->cogl_tex_id[0]); /* Create new texture from modified data */ priv->cogl_tex_id[1] = cogl_texture_new_from_data (width, height, 0, FALSE, format, format, rowstride, data); if (priv->cogl_tex_id[1] == COGL_INVALID_HANDLE) { printf ("Failed creating image from data!\n"); return; } printf ("Texture created from data.\n"); /* Modify data (swap red and green) */ for (y=0; y<height; ++y) { for (x=0; x<width; ++x) { pixel = data + y * rowstride + x * 4; if (format == COGL_PIXEL_FORMAT_RGBA_8888) { t = pixel[0]; pixel[0] = pixel[1]; pixel[1] = t; } else { t = pixel[1]; pixel[1] = pixel[2]; pixel[2] = t; } } } cogl_texture_set_region (priv->cogl_tex_id[1], 0, 0, 0, 0, 100, 100, width, height, format, 0, data); cogl_texture_set_region (priv->cogl_tex_id[1], 100, 100, 100, 100, 100, 100, width, height, format, 0, data); printf ("Subregion data updated.\n"); }