cgtkcairogdkpixbuf

GTK+ Replace gdk_draw_pixbuf with Cairo


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?


Solution

  • 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).