cairo-templates.h revision ccb10249f38c4a7f561a027c1e4f700ec9ba86bd
2N/A * @brief Cairo software blending templates 2N/A * Krzysztof KosiĆski <tweenk.pl@gmail.com> 2N/A * Copyright (C) 2010 Authors 2N/A * Released under GNU GPL, read the file 'COPYING' for more information 2N/A// single-threaded operation if the number of pixels is below this threshold 2N/A * @brief Blend two surfaces using the supplied functor. 2N/A * This template blends two Cairo image surfaces using a blending functor that takes 2N/A * two 32-bit ARGB pixel values and returns a modified 32-bit pixel value. 2N/A * Differences in input surface formats are handled transparently. In future, this template 2N/A * will also handle software fallback for GL surfaces. */ 2N/A // 1. Cairo ARGB32 surface strides are always divisible by 4 2N/A // 2. We can only receive CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_A8 surfaces 2N/A // 3. Both surfaces are of the same size 2N/A // 4. Output surface is ARGB32 if at least one input is ARGB32 2N/A // Check whether we can loop over pixels without taking stride into account. 2N/A // OpenMP probably doesn't help much here. 2N/A // It would be better to render more than 1 tile at a time. 2N/A // The number of code paths here is evil. 2N/A for (
int i = 0; i < h; ++i) {
2N/A for (
int j = 0; j < w; ++j) {
2N/A for (
int i = 0; i < h; ++i) {
2N/A for (
int j = 0; j < w; ++j) {
2N/A for (
int i = 0; i < h; ++i) {
2N/A for (
int j = 0; j < w; ++j) {
2N/A // bpp1 == 1 && bpp2 == 1 2N/A for (
int i = 0; i < h; ++i) {
2N/A for (
int j = 0; j < w; ++j) {
2N/A // 1. Cairo ARGB32 surface strides are always divisible by 4 2N/A // 2. We can only receive CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_A8 surfaces 2N/A // 3. Surfaces have the same dimensions 2N/A // 4. Output surface is A8 if input is A8 2N/A // Check whether we can loop over pixels without taking stride into account. 2N/A // bppin == 4, bppout == 4 2N/A for (
int i = 0; i < h; ++i) {
2N/A for (
int j = 0; j < w; ++j) {
2N/A // bppin == 4, bppout == 1 2N/A // we use this path with COLORMATRIX_LUMINANCETOALPHA 2N/A for (
int i = 0; i < h; ++i) {
2N/A for (
int j = 0; j < w; ++j) {
2N/A // bppin == 1, bppout == 1 2N/A // Note: there is no path for bppin == 1, bppout == 4 because it is useless 2N/A for (
int i = 0; i < h; ++i) {
2N/A for (
int j = 0; j < w; ++j) {
2N/A * @brief Synthesize surface pixels based on their position. 2N/A * This template accepts a functor that gets called with the x and y coordinates of the pixels, 2N/A * given as integers. 2N/A * @param out Output surface 2N/A * @param out_area The region of the output surface that should be synthesized 2N/A * @param synth Synthesis functor */ 2N/A // 1. Cairo ARGB32 surface strides are always divisible by 4 2N/A // 2. We can only receive CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_A8 surfaces 2N/A // NOTE: fast path is not used, because we would need 2 divisions to get pixel indices 2N/A return (p &
0xff000000) >>
24;
2N/A // retrieve a pixel value with bilinear interpolation 2N/A for (
unsigned i = 0; i <
4; ++i) {
2N/A // retrieve an alpha value with bilinear interpolation 2N/A // compute surface normal at given coordinates using 3x3 Sobel gradient filter 2N/A // Below there are some multiplies by zero. They will be optimized out. 2N/A // Do not remove them, because they improve readability. 2N/A // NOTE: fetching using alphaAt is slightly lazy. 2N/A // upper left corner 2N/A // lower left corner 2N/A +
0.0 *
p01 +
0.0 *
p11 // this will be optimized out 2N/A // bottom right corner 2N/A // note: p11 is actually unused, so we don't fetch its value 2N/A// simple pixel accessor for image surface that handles different edge wrapping modes 2N/Aclass PixelAccessor { typedef PixelAccessor self; PixelAccessor(cairo_surface_t *s, EdgeMode e) , _px(cairo_image_surface_get_data(s)) , _w(cairo_image_surface_get_width(s)) , _h(cairo_image_surface_get_height(s)) , _stride(cairo_image_surface_get_stride(s)) , _alpha(cairo_image_surface_get_format(s) == CAIRO_FORMAT_A8) guint32 pixelAt(int x, int y) { // This is a lot of ifs for a single pixel access. However, branch prediction // should help us a lot, as the result of ifs is always the same for a single image. int real_x = x, real_y = y; real_x = CLAMP(x, 0, _w-1); real_y = CLAMP(y, 0, _h-1); if (x < 0 || x >= _w || y < 0 || y >= _h) return *(_px + real_y*_stride + real_x) << 24; guint32 *px = reinterpret_cast<guint32*>(_px +real_y*_stride + real_x*4); cairo_surface_t *_surface; int _x, _y, _w, _h, _stride; // Some helpers for pixel manipulation // NOTE: it is possible to write a "branchless" clamping operation. // However, it will be slower than this function, because the code below // is compiled to conditional moves. a = (
px &
0xff000000) >>
24; \
r = (
px &
0x00ff0000) >>
16; \
g = (
px &
0x0000ff00) >>
8; \
guint32 px = (a <<
24) | (r <<
16) | (g <<
8) | b;
c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :