[comp.windows.x] GXinvert & planes

brian@natinst.com (Brian H. Powell) (12/11/90)

     I was trying to invert some text (drawn with Xlib) to show a selection.
At first, I made a GC with a function of GXinvert, and a plane_mask of the
default AllPlanes.  This worked fine under OpenWindows, but failed under
the Sun MIT server (it drew all black).
     I went looking for some sample client code, and found a couple of
different examples where the plane_mask was set to the exclusive-or of the
foreground and background colors.  I tried this, and it worked.  But I didn't
understand why.  Perhaps it's because I'm not a color guru.
     Can somebody mail me an explanation of why it's done this way?  Thanks.

Brian H. Powell, M/S 56-14			National Instruments Corp.
	brian@natinst.com			6504 Bridge Point Parkway
	uunet!cs.utexas.edu!natinst!brian	Austin, Texas 78730-5039
	AppleLink:NATINST			(512) 338-9119

cflatter@ZIA.AOC.NRAO.EDU (Chris Flatters) (12/12/90)

Brian Powell writes:
>     I was trying to invert some text (drawn with Xlib) to show a selection.
> At first, I made a GC with a function of GXinvert, and a plane_mask of the
> default AllPlanes.  This worked fine under OpenWindows, but failed under
> the Sun MIT server (it drew all black).
>     I went looking for some sample client code, and found a couple of
> different examples where the plane_mask was set to the exclusive-or of the
> foreground and background colors.  I tried this, and it worked.  But I didn't
> understand why.  Perhaps it's because I'm not a color guru.

Suppose that the bits in the index of the background colour are b(0) ... b(depth-1) and the bits in the index of the foreground colour are f(0) ...
f(depth-1).  Applying GXinvert to a colour with index c (with bits c(0) ...
c(depth-1) will produce a colour with bits not(c(0)) ... not(c(depth-1).
In order for this to reverse the foreground and background colours we
require

        f(i) = not(b(i)) for all i: 0..depth-1

This is clearly not true in all cases.  Take for example the case where
the foreground has index 1 (0000 0001 in binary) and the background has
index 0 (0000 0000): the inverted bit patterns are 1111 1110 and 1111 1111.
This case is interesting since black appears both at index 1 and 254 in
the initial X11/NeWS colormap on 8-bit colour displays and white appears
at indices 0 and 255:  thus a straight invert of the display will appear
to work.

Suppose we now add a plane mask with bits m(i).  If the initial colour
at a given pixel is c then the output bits are

       (m(i) and not(c(i))) or (not(m(i)) and c(i))

(recall that if the i-th bit of the mask is 0 then the source pixel is
unchanged).  If we set the mask to the exclusive or of f and b the
the output bits are

	o(c(i)) = ((f(i) xor b(i)) and not(c(i))) or
                  (not (f(i) xor b(i)) and c(i))

You may verify that 

        o(f(i)) = b(i)
 and
        o(b(i)) = f(i)

(as required) by Boolean algebra or by constructing truth tables.

			Chris Flatters

whaley@spectre.pa.dec.com (Ken Whaley) (12/12/90)

Just on the off chance that you haven't received thousands of responses by now,
I'll try to give you a brief explanation as to why just using 
GXinvert + AllPlanes won't give you the correct results almost all of the time
on a color display.  Since I wish someone had explained something 
like this to me a long time ago, I'll post this to the net in the case that 
others might want to learn the pleasures of pixel bit twiddling.

First of all, I'm assuming that what you want to do is reverse the foreground
and background values to highlight the text string.  There are several ways
to combine boolean functions and plane masks to achieve this effect, but you 
basically want to take two arbitrary pixel values (your GC foreground and 
background colors) and swap them.  I assume you draw a rectangle over the 
region you want to highlight with function = GXinvert.

Assume foreground pixel (fg) = 	5	(00000101 binary)
Assume background pixel (bg) =  16	(00010000 binary)

(It doesn't matter what colors are assigned to these values--what's important
is the pixel values themselves.)

By applying the invert operation with plane mask AllPlanes, you invert
every bit in the fg and bg pixels

Inverted fg: 11111010 (binary), 0xFA
Inverted bg: 11101111 (binary), 0xEF

Now, chances are (unless you run applications that fill up the colormap) that 
you have "black" stored at pixel values 0xFA and 0xEF, which explains why you 
see black on the screen.

If you set the planemask to fg^bg ("^" is xor), then the planemask is 00010101

Inverted fg & planemask = 11111010
			& 00010101
			----------
			  00010000  = bg

Inverted bg & planemask = 11101111
			& 00010101
			----------
			  00000101  = fg

By setting planemask = fg^bg, you say that you only want to invert
the bits in fg/bg that are different from bg/fg, so that fg-->bg and bg-->fg,
which is exactly what you want (note that this works when fg & bg != 0, because
1^1 = 0, and so that bit won't change).

	Ken

whaley@spectre.enet.dec.com (Ken Whaley) (12/12/90)

Sorry if this is a repeat, but my poster is flaky today.

Just on the off chance that you haven't received thousands of responses by now,
I'll try to give you a brief explanation as to why just using 
GXinvert + AllPlanes won't give you the correct results almost all of the time
on a color display.  Since I wish someone had explained something 
like this to me a long time ago, I'll post this to the net in the case that 
others might want to learn the pleasures of pixel bit twiddling.

First of all, I'm assuming that what you want to do is reverse the foreground
and background values to highlight the text string.  There are several ways
to combine boolean functions and plane masks to achieve this effect, but you 
basically want to take two arbitrary pixel values (your GC foreground and 
background colors) and swap them.  I assume you draw a rectangle over the 
region you want to highlight with function = GXinvert.

Assume foreground pixel (fg) = 	5	(00000101 binary)
Assume background pixel (bg) =  16	(00010000 binary)

(It doesn't matter what colors are assigned to these values--what's important
is the pixel values themselves.)

By applying the invert operation with plane mask AllPlanes, you invert
every bit in the fg and bg pixels

Inverted fg: 11111010 (binary), 0xFA
Inverted bg: 11101111 (binary), 0xEF

Now, chances are (unless you run applications that fill up the colormap) that 
you have "black" stored at pixel values 0xFA and 0xEF, which explains why you 
see black on the screen.

If you set the planemask to fg^bg ("^" is xor), then the planemask is 00010101

Inverted fg & planemask = 11111010
			& 00010101
			----------
			  00010000  = bg

Inverted bg & planemask = 11101111
			& 00010101
			----------
			  00000101  = fg

By setting planemask = fg^bg, you say that you only want to invert
the bits in fg/bg that are different from bg/fg, so that fg-->bg and bg-->fg,
which is exactly what you want (note that this works when fg & bg != 0, because
1^1 = 0, and so that bit won't change).

	Ken