Clipping using a bitmap: clipbit.c

The module clipbit.c employees a different tecnique of defining the clipping area.

For clipping, any number of rectangles can be used. However, the result is guaranteed to be correct only if they are non-intersecting. The most general way of implementing clipping uses a pixmap with depht 1. In this pixmap, black pixel represents points not to be copied, and white pixel are points that will be copied. After creating such a pixmap, it can be included in the graphic context using the function XSetClipMask. This is what is done in the module clipbit.c. First of all, we need a bitmap (a pixmap with depth 1), and a graphic context for it:

  /* create the clipping mask */
  clip_mask = XCreatePixmap(dpy, double_buffer, wa.width, wa.height, 1);
  gc=XCreateGC (dpy, clip_mask, 0, NULL);
Each point of this bitmap tells X which pixels to copy when XCopyArea is called: a pixel set to 0 in this bitmap means that the pixel of the same coordinates is not to be copied, while a pixel set to 1 means ``copy''.

At each step, we first clean the bitmap (so points will not be copied by default):

      /* clear clipping mask */
      XSetBackground(dpy, gc, 0);
      XFillRectangle(dpy, clip_mask, gc, 0, 0, wa.width, wa.height);
Each time we draw something in the double buffer, we write 1 in the same points of the clipping mask to indicate that this region has been changed in the buffer, so it is to be copied. The erasure of the ball from the old position becomes:
      /* remove the ball from the screen */
      XSetForeground(dpy, g, BlackPixelOfScreen(DefaultScreenOfDisplay(dpy)));
      XFillArc(dpy, double_buffer, g, x, y, 40, 40, 0, 360*64);


      /* region changed, set mask */
      XSetForeground(dpy, gc, 1);
      XFillArc(dpy, clip_mask, gc, x, y, 40, 40, 0, 360*64);
While the redraw in the new position is:
      /* draw in the new position */
      XSetForeground(dpy, g, reds.pixel);
      XFillArc(dpy, double_buffer, g, x, y, 40, 40, 0, 360*64);


      /* region changed, set mask */
      XSetForeground(dpy, gc, 1);
      XFillArc(dpy, clip_mask, gc, x, y, 40, 40, 0, 360*64);
Before actually doing the copy, we have to specify that clip_mask is clipping mask we want to use. This is what XSetClipMask does:
      /* set clipping mask */
      XSetClipMask(dpy, g, clip_mask);


      /* copy the buffer to the window */
      XCopyArea(dpy, double_buffer, root, g, 0, 0, wa.width, wa.height, 0, 0);
Note that gc is the graphic context to use for drawing in the bitmap. This means that all operations on the bitmap must use gc instead of g. Copying an area is instead an operation on the window and the pixmap, so the graphics context it uses is g. The clipping mask is an element of g, and this is why g is the second argument we pass to XSetClipMask. This just to say that some care has to be taken for not confusing the graphics contexts.


Next: clipping origin