CoglPipeline * _st_create_shadow_pipeline (StShadow *shadow_spec, CoglTexture *src_texture) { ClutterBackend *backend = clutter_get_default_backend (); CoglContext *ctx = clutter_backend_get_cogl_context (backend); static CoglPipeline *shadow_pipeline_template = NULL; CoglPipeline *pipeline; CoglTexture *texture; guchar *pixels_in, *pixels_out; gint width_in, height_in, rowstride_in; gint width_out, height_out, rowstride_out; g_return_val_if_fail (shadow_spec != NULL, NULL); g_return_val_if_fail (src_texture != NULL, NULL); width_in = cogl_texture_get_width (src_texture); height_in = cogl_texture_get_height (src_texture); rowstride_in = (width_in + 3) & ~3; pixels_in = g_malloc0 (rowstride_in * height_in); cogl_texture_get_data (src_texture, COGL_PIXEL_FORMAT_A_8, rowstride_in, pixels_in); pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in, shadow_spec->blur, &width_out, &height_out, &rowstride_out); g_free (pixels_in); texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, width_out, height_out, COGL_PIXEL_FORMAT_A_8, rowstride_out, pixels_out, NULL)); g_free (pixels_out); if (G_UNLIKELY (shadow_pipeline_template == NULL)) { CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); shadow_pipeline_template = cogl_pipeline_new (ctx); /* We set up the pipeline to blend the shadow texture with the combine * constant, but defer setting the latter until painting, so that we can * take the actor's overall opacity into account. */ cogl_pipeline_set_layer_combine (shadow_pipeline_template, 0, "RGBA = MODULATE (CONSTANT, TEXTURE[A])", NULL); } pipeline = cogl_pipeline_copy (shadow_pipeline_template); cogl_pipeline_set_layer_texture (pipeline, 0, texture); cogl_object_unref (texture); return pipeline; }
CoglHandle _st_create_shadow_material (StShadow *shadow_spec, CoglHandle src_texture) { static CoglHandle shadow_material_template = COGL_INVALID_HANDLE; CoglHandle material; CoglHandle texture; guchar *pixels_in, *pixels_out; gint width_in, height_in, rowstride_in; gint width_out, height_out, rowstride_out; g_return_val_if_fail (shadow_spec != NULL, COGL_INVALID_HANDLE); g_return_val_if_fail (src_texture != COGL_INVALID_HANDLE, COGL_INVALID_HANDLE); width_in = cogl_texture_get_width (src_texture); height_in = cogl_texture_get_height (src_texture); rowstride_in = (width_in + 3) & ~3; pixels_in = g_malloc0 (rowstride_in * height_in); cogl_texture_get_data (src_texture, COGL_PIXEL_FORMAT_A_8, rowstride_in, pixels_in); pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in, shadow_spec->blur, &width_out, &height_out, &rowstride_out); g_free (pixels_in); texture = cogl_texture_new_from_data (width_out, height_out, COGL_TEXTURE_NONE, COGL_PIXEL_FORMAT_A_8, COGL_PIXEL_FORMAT_A_8, rowstride_out, pixels_out); g_free (pixels_out); if (G_UNLIKELY (shadow_material_template == COGL_INVALID_HANDLE)) { shadow_material_template = cogl_material_new (); /* We set up the material to blend the shadow texture with the combine * constant, but defer setting the latter until painting, so that we can * take the actor's overall opacity into account. */ cogl_material_set_layer_combine (shadow_material_template, 0, "RGBA = MODULATE (CONSTANT, TEXTURE[A])", NULL); } material = cogl_material_copy (shadow_material_template); cogl_material_set_layer (material, 0, texture); cogl_handle_unref (texture); return material; }
/** * _st_create_shadow_cairo_pattern: * @shadow_spec: the definition of the shadow * @src_pattern: surface pattern for which we create the shadow * (must be a surface pattern) * * This is a utility function for creating shadows used by * st-theme-node.c; it's in this file to share the gaussian * blur implementation. The usage of this function is quite different * depending on whether shadow_spec->inset is %TRUE or not. If * shadow_spec->inset is %TRUE, the caller should pass in a @src_pattern * which is the <i>inverse</i> of what they want shadowed, and must take * care of the spread and offset from the shadow spec themselves. If * shadow_spec->inset is %FALSE then the caller should pass in what they * want shadowed directly, and this function takes care of the spread and * the offset. */ cairo_pattern_t * _st_create_shadow_cairo_pattern (StShadow *shadow_spec, cairo_pattern_t *src_pattern) { static cairo_user_data_key_t shadow_pattern_user_data; cairo_t *cr; cairo_surface_t *src_surface; cairo_surface_t *surface_in; cairo_surface_t *surface_out; cairo_pattern_t *dst_pattern; guchar *pixels_in, *pixels_out; gint width_in, height_in, rowstride_in; gint width_out, height_out, rowstride_out; cairo_matrix_t shadow_matrix; int i, j; g_return_val_if_fail (shadow_spec != NULL, NULL); g_return_val_if_fail (src_pattern != NULL, NULL); cairo_pattern_get_surface (src_pattern, &src_surface); width_in = cairo_image_surface_get_width (src_surface); height_in = cairo_image_surface_get_height (src_surface); /* We want the output to be a color agnostic alpha mask, * so we need to strip the color channels from the input */ if (cairo_image_surface_get_format (src_surface) != CAIRO_FORMAT_A8) { surface_in = cairo_image_surface_create (CAIRO_FORMAT_A8, width_in, height_in); cr = cairo_create (surface_in); cairo_set_source_surface (cr, src_surface, 0, 0); cairo_paint (cr); cairo_destroy (cr); } else { surface_in = cairo_surface_reference (src_surface); } pixels_in = cairo_image_surface_get_data (surface_in); rowstride_in = cairo_image_surface_get_stride (surface_in); pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in, shadow_spec->blur, &width_out, &height_out, &rowstride_out); cairo_surface_destroy (surface_in); /* Invert pixels for inset shadows */ if (shadow_spec->inset) { for (j = 0; j < height_out; j++) { guchar *p = pixels_out + rowstride_out * j; for (i = 0; i < width_out; i++, p++) *p = ~*p; } } surface_out = cairo_image_surface_create_for_data (pixels_out, CAIRO_FORMAT_A8, width_out, height_out, rowstride_out); cairo_surface_set_user_data (surface_out, &shadow_pattern_user_data, pixels_out, (cairo_destroy_func_t) g_free); dst_pattern = cairo_pattern_create_for_surface (surface_out); cairo_surface_destroy (surface_out); cairo_pattern_get_matrix (src_pattern, &shadow_matrix); if (shadow_spec->inset) { /* For inset shadows, offsets and spread radius have already been * applied to the original pattern, so all left to do is shift the * blurred image left, so that it aligns centered under the * unblurred one */ cairo_matrix_translate (&shadow_matrix, (width_out - width_in) / 2.0, (height_out - height_in) / 2.0); cairo_pattern_set_matrix (dst_pattern, &shadow_matrix); return dst_pattern; } /* Read all the code from the cairo_pattern_set_matrix call * at the end of this function to here from bottom to top, * because each new affine transformation is applied in * front of all the previous ones */ /* 6. Invert the matrix back */ cairo_matrix_invert (&shadow_matrix); /* 5. Adjust based on specified offsets */ cairo_matrix_translate (&shadow_matrix, shadow_spec->xoffset, shadow_spec->yoffset); /* 4. Recenter the newly scaled image */ cairo_matrix_translate (&shadow_matrix, - shadow_spec->spread, - shadow_spec->spread); /* 3. Scale up the blurred image to fill the spread */ cairo_matrix_scale (&shadow_matrix, (width_in + 2.0 * shadow_spec->spread) / width_in, (height_in + 2.0 * shadow_spec->spread) / height_in); /* 2. Shift the blurred image left, so that it aligns centered * under the unblurred one */ cairo_matrix_translate (&shadow_matrix, - (width_out - width_in) / 2.0, - (height_out - height_in) / 2.0); /* 1. Invert the matrix so we can work with it in pattern space */ cairo_matrix_invert (&shadow_matrix); cairo_pattern_set_matrix (dst_pattern, &shadow_matrix); return dst_pattern; }
void UnsharpUnit::process_package(LoadPackage *package) { UnsharpPackage *pkg = (UnsharpPackage*)package; // int w = server->src->get_w(); // int h = server->src->get_h(); int color_model = server->src->get_color_model(); int components = BC_CModels::components(color_model); double *cmatrix = 0; int cmatrix_length = 0; int padded_y1 = pkg->y1; int padded_y2 = pkg->y2; cmatrix_length = calculate_convolution_matrix( plugin->config.radius, &cmatrix); if(padded_y2 < server->src->get_h()) { padded_y2 += cmatrix_length / 2; padded_y2 = MIN(server->src->get_h(), padded_y2); } if(padded_y1 > 0) { padded_y1 -= cmatrix_length / 2; padded_y1 = MAX(0, padded_y1); } int padded_rows = padded_y2 - padded_y1; if(!temp || temp->get_h() != padded_rows) { delete temp; temp = 0; } if(!temp) { temp = new VFrame; temp->set_use_shm(0); temp->reallocate(0, -1, 0, 0, 0, server->src->get_w(), padded_rows, components == 3 ? BC_RGB_FLOAT : BC_RGBA_FLOAT, -1); } float *temp_in = new float[MAX(temp->get_w(), padded_rows) * components]; float *temp_out = new float[MAX(temp->get_w(), padded_rows) * components]; // Blur rows for(int i = padded_y1; i < padded_y2; i++) { get_row(temp_in, server->src, i); blur_pixels(cmatrix, cmatrix_length, temp_in, temp_out, temp->get_w(), components); // printf("UnsharpUnit::process_package %d %p %p %p %d %d\n", // __LINE__, // temp, // temp->get_rows()[0], // temp_out, // i - padded_y1, // temp->get_bytes_per_line()); memcpy(temp->get_rows()[i - padded_y1], temp_out, temp->get_bytes_per_line()); } //Now we're 100% floating point. Blur the columns for(int i = 0; i < temp->get_w(); i++) { get_column(temp_in, temp, i); blur_pixels(cmatrix, cmatrix_length, temp_in, temp_out, padded_rows, components); put_column(temp_out, temp, i); } //printf("%f %f %d\n", plugin->config.radius,plugin->config.amount, plugin->config.threshold); #define UNSHARPEN(type, components, max) \ { \ float threshold = (float)plugin->config.threshold * max / 0xff; \ float amount = plugin->config.amount; \ \ for(int i = pkg->y1; i < pkg->y2; i++) \ { \ float *blurry_row = (float*)temp->get_rows()[i - padded_y1]; \ type *orig_row = (type*)server->src->get_rows()[i]; \ for(int j = 0; j < server->src->get_w(); j++) \ { \ for(int k = 0; k < components; k++) \ { \ float diff = *orig_row - *blurry_row; \ if(fabsf(2 * diff) < threshold) \ diff = 0; \ float value = *orig_row + amount * diff; \ if(sizeof(type) == 4) \ *orig_row = (type)value; \ else \ *orig_row = (type)CLIP(value, 0, max); \ blurry_row++; \ orig_row++; \ } \ } \ } \ } // Apply unsharpening switch(color_model) { case BC_RGB888: case BC_YUV888: UNSHARPEN(unsigned char, 3, 0xff); break; case BC_RGBA8888: case BC_YUVA8888: UNSHARPEN(unsigned char, 4, 0xff); break; case BC_RGB_FLOAT: UNSHARPEN(float, 3, 1.0); break; case BC_RGBA_FLOAT: UNSHARPEN(float, 4, 1.0); break; case BC_YUV161616: UNSHARPEN(uint16_t, 3, 0xffff); break; case BC_YUVA16161616: UNSHARPEN(uint16_t, 4, 0xffff); break; } delete [] temp_in; delete [] temp_out; delete [] cmatrix; }