1
votes

I'm working on a GtkDrawingArea which, in the expose event, is drawing a section of a pixbuf in a tiled manner. The tiling type varies - depending on the source image; it can be orthogonal, isometric or hexagonal. Drawing this with gdk_draw_pixmap is simple enough; here is an example on how it looks for isometric tiling:

for(y=0,row=0; y+tile_height<height; y+=tile_half_height,++row)
  for(x=((row&1)? tile_half_width : 0); x+tile_width<width; x+=tile_width)
    gdk_draw_pixbuf(widget->window,NULL,
                    pixbuf,src_x,src_y,
                    x,y,tile_width,tile_height,
                    GDK_RGB_DITHER_NONE,0,0);

Result:

Isometric tiling with gdk_draw_pixbuf

However, drawing the same with Cairo proved to be quite not the same. This is what I have so far, which isn't working:

cairo_t *cr = gdk_cairo_create(widget->window);
gdk_cairo_set_source_pixbuf(cr,pixbuf,src_x,src_y);
for(y=0,row=0; y+tile_height<height; y+=tile_half_height,++row)
  for(x=((row&1)? tile_half_width : 0); x+tile_width<width; x+=tile_width) {
    cairo_rectangle(cr,x,y,tile_width,tile_height);
    cairo_paint(cr);
  }
}
cairo_destroy(cr);

Result:

Isometric tiling with Cairo

Cairo simply refuses to draw the image as a normal raster image would be drawn. What am I doing wrong, how is this solved?

1
cairo_paint() fills the clip region, not the current path; you will need to convert the path you created with cairo_rectangle() into a clip region with cairo_clip(). (Remember that the clip region is preserved over time, so you will also need cairo_save() and cairo_restore() in your for loop.)andlabs
I don't know how cairo_fill handles image sources; you could try that. I've only ever used it with solid colors.oldtechaa
Nope, same result. The problem is that the entire source image is used as the pattern, even when I only want to use a section of it. I need to fix src_x, src_y, which isn't happening in Cairo - src_x, src_y is simply the starting point in the source image, then it adjusts in the source image by x, y accordingly.Per Löwgren
I've also tried combinations of cairo_translate(), but it seems trial and error amounts to infinity in this case, that's why I ask.Per Löwgren

1 Answers

2
votes

Untested, but might work. If not, then report back and I'll try again:

static void _cairo_gdk_draw_pixbuf(cairo_t *cr, cairo_surface_t *source,
        int src_x, int src_y,
        int dest_x, int dest_y,
        int width, int height)
{
    cairo_save(cr);

    /* Move (0, 0) to the destination position */
    cairo_translate(cr, dest_x, dest_y);

    /* Set up the source surface in such a way that (src_x, src_y) maps to
     * (0, 0) in user coordinates. */
    cairo_set_source_surface(cr, source, -src_x, -src_y);

    /* Do the drawing */
    cairo_rectangle(cr, 0, 0, width, height);
    cairo_fill(cr);

    /* Undo all of our modifications to the drawing state */
    cairo_restore(cr);
}

The above function should work like gdk_draw_pixbuf (well, similar to it).