brown@ftms.UUCP (Vidiot) (02/21/91)
We are using OpenLook under SunOS 4.1. The programmer is using the GXxor function in the graphics context for Xlib calls. We get the following results: draw color background result expect black black white black white white tan(?) black red red white black red blue aquamarine(?)/ magenta cyan blue blue white black Can someone explain why we are not getting the expected results? Is there a formula that can be used to determine ahead of time what the results will be? Thanks in advance. -- harvard\ ucbvax!uwvax!astroatc!ftms!brown rutgers/ INTERNET: spool.cs.wisc.edu!astroatc!ftms!brown
whaley@spectre.pa.dec.com (Ken Whaley) (02/22/91)
> draw color background result expect > > black black white black > white white tan(?) black > red red white black > red blue aquamarine(?)/ magenta > cyan > blue blue white black > >Can someone explain why we are not getting the expected results? Is there >a formula that can be used to determine ahead of time what the results will >be? Ah, color XORing, my favorite topic! :) Maybe this should be added to the FAQ list? I'd be glad to write the entry. Anyway, here goes. Basically, if you care about what colors result from XORing pixel values in your application, you must make certain preparations. Otherwise, you'll get apparently random results (as you have) which depend on what colors are already in the colormap. As an example, let's consider the 8-plane PseudoColor case, which is a common color system that most people have. This colormap has 256 entries, each of which can be set to produce any color your system is capable of displaying. Suppose your colors are red and blue and suppose they have pixel values 3 and 5, and your GC has foreground==red, background==blue, function==XOR. red XOR red == 3 XOR 3 == 0, so whatever color has pixel value zero is displayed when you draw over red with red. So, since combining equal colors gives you white (except for white+white = tan, which means you must have more than one pixel value for white), your white has pixel value 0. Now, drawing blue on red or red on blue results in pixel value 3 XOR 5, or 6. Whatever color is at pixel value 6 in your colormap is displayed here. The strange colors you're seeing have a pixel value equal to that of the XOR of the two colors you're combining, and might have been set by a different application which allocated colors from the default colormap. In general, if you'd like to use XOR to flip between two arbitrary colors (fg and bg), set up an XOR-ing GC with function = XOR, foreground = fg ^ bg, and background = 0 ("^" is XOR in C). To apply this to our case, foreground = red ^ blue (== 3 ^ 5 == 6). Then, drawing over red with this GC results in: foreground ^ red == 6 ^ 3 == 5 == blue and drawing over blue results in: foreground ^ blue == 6 ^ 5 == 3 == red. Voila! It's a little more complicated when you want to combine colors rather than switch between them, and if many colors are involved, it gets yet more complicated. Basically, you want to use XAllocColorCells with one pixel and several planes to allocate consecutive color planes, then to store colors into specific pixel values so that XORing works the way you want. If you want to use "overlay planes" instead of XORing, you call XAllocColorCells with several base colors and the number of overlay planes you want, and then set up colors for each combination of base pixel value + overlay plane (+ overlay plane....). Rough Example: using XOR to combine colors (in a reversible way, i.e., drawing again erases the first draw) with XAllocColorCells (one color, 3 planes) 0 is your window background color 1, 2, and 4 are your drawing colors XOR table: draw color background color result --------- ---------------- ----- 1 0 1 (1^1 == 0, also) 1 2 3 (1^3 == 2, also) 1 4 5 (1^5 == 4, also...etc) 2 0 2 2 1 3 2 4 6 4 0 4 4 1 5 4 2 6 Using this table, you allocate 0, 1, 2, 3, 4, 5, 6 to whatever you want them to be, and you can "rubber band" with either color 1, 2, or 4. Now, you don't really get these values literally; you get them allocated to you as consecutive planes + a base pixel, which means the actual pixel values might be (in binary, assuming a base pixel value of 101): 0---0101 where "---" ranges from 000 to 111 in binary. These values correspond to the numbers used in the table above. You select your drawing color through the plane_mask, and set your foreground to 0xff (all ones). Below is an example program that calls XAllocColorCells to get 3 consecutive color planes, sets up the colors, and draws each of the drawing colors on top of each other and the combined colors. It comes up and displays horizontal lines of the drawing colors (1, 2, 4) and the combined colors (3, 5, 6) against a background of color 0. When you press a key in the window, it draws the drawing colors vertically in XOR mode. Press a key again and they vanish (are drawn again), thanks to the magic of XOR. Note that there are a 3 colors here (marked "X" ) that won't occur if you use a "draw then erase" (as in rubber banding) technique (which is what most people use XOR for in the first place). 1 2 4 1 2 4 3 X 5 X 6 X 0 Use the table by looking at the leftmost color on each row, and choosing a column (corresponds to drawing color...look at last row to see which one). Whew! I hope that this is helpful! Ken Save in "file.c", and compile with "cc -o colortest file.c -lX11" ---------------------CUT HERE----------------------- #include <X11/Xlib.h> #include <X11/X.h> #define PIXEL(x) (((x) << shift) | pixel) unsigned long plane_masks[6]; unsigned long pixel; Status result; int shift, i; GC gc; XEvent e; Display *d; int scr; Colormap cm; Window w, r; main() { int mode = 0; int flags = {DoRed | DoGreen | DoBlue}; d = XOpenDisplay(""); scr = XDefaultScreen(d); cm = DefaultColormap(d, scr); r = DefaultRootWindow(d); result = XAllocColorCells(d, cm, True, plane_masks, 3, &pixel, 1); if (!result) { printf("allocation failed.\n"); exit(1); } /* find the location of the first bit plane */ for (shift = 0; plane_masks[0] != (1 << shift); shift++) ; XStoreNamedColor(d, cm, "White", PIXEL(0), flags); XStoreNamedColor(d, cm, "Red", PIXEL(1), flags); XStoreNamedColor(d, cm, "Blue", PIXEL(2), flags); XStoreNamedColor(d, cm, "Magenta", PIXEL(3), flags); XStoreNamedColor(d, cm, "Black", PIXEL(4), flags); XStoreNamedColor(d, cm, "Yellow", PIXEL(5), flags); XStoreNamedColor(d, cm, "Green", PIXEL(6), flags); w = XCreateSimpleWindow(d, r, 10, 10, 400, 700, 0, 0, PIXEL(0)); gc = DefaultGC(d, scr); XSelectInput(d, w, ExposureMask | KeyPressMask); XMapWindow(d, w); while(1) { XNextEvent(d, &e); switch(e.type) { case Expose: setup(); if (mode) combine(); break; case KeyPress: mode ^= 1; combine(); break; } } } setup() { XClearWindow(d, w); XSetForeground(d, gc, 0xff); XSetFunction(d, gc, GXxor); /* draw "drawing" colors horizontally against the * background color. */ for (i = 0; i < 3; i++) { XSetPlaneMask(d, gc, plane_masks[i]); XFillRectangle(d, w, gc, 0, i*100, 400, 100); } XSetPlaneMask(d, gc, 0xff); XSetFunction(d, gc, GXcopy); /* draw the "combined" colors to show that the drawing colors * revert them back to the original colors. */ XSetForeground(d, gc, PIXEL(3)); XFillRectangle(d, w, gc, 0, 300, 400, 100); XSetForeground(d, gc, PIXEL(5)); XFillRectangle(d, w, gc, 0, 400, 400, 100); XSetForeground(d, gc, PIXEL(6)); XFillRectangle(d, w, gc, 0, 500, 400, 100); } combine() { XSetForeground(d, gc, 0xff); XSetFunction(d, gc, GXxor); /* Now draw the "drawing" colors over each of the drawing * and combined colors to show the combined ones go back * to the original corresponding drawing color */ for (i = 0; i < 3; i++) { XSetPlaneMask(d, gc, plane_masks[i]); XFillRectangle(d, w, gc, (i+1)*100, 0, 100, 700); } } -- ^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^ /----\// / // Ken Whaley / :) // \ whaley@atd.dec.com | :-)// | | //;-)| Help stamp out smileys! |;)// | | // :) | // :-) / //\____/ ^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^
chuck@Morgan.COM (Chuck Ocheret) (02/28/91)
> We are using OpenLook under SunOS 4.1. The programmer is using the GXxor > function in the graphics context for Xlib calls. We get the following results: > > draw color background result expect > > black black white black > white white tan(?) black > red red white black > red blue aquamarine(?)/ magenta > cyan > blue blue white black > > Can someone explain why we are not getting the expected results? Is there > a formula that can be used to determine ahead of time what the results will > be? Xoring pixels operates on bits, not on names. Depending on your server and the Visual you are using you cannot expect particular colors to have particular pixel values. Basically, colors can be allocated to arbitrary cells in the colormap. To accomplish what it looks like you are trying to do you should be Xor drawing with your foreground pixel set to a value which is an Xor of the displayed pixel and the desired color's pixel. For example, let's say that you allocate the following colors on a 4 bit deep display. color name pixel allocated(treat these as completely arbitrary) ---------- --------------- red 0x5 blue 0xf magenta 0x8 green 0xa Let's also say that most of your window has been drawn in blue and you want to do Xor drawing (e.g. rubber band line) that appears magenta. Don't try to draw in red 0x5 (Xor does not do color blending unless you are real lucky with your color map). If you were to Xor draw in red the blue pixels will get changed from 0xf to 0xa = green. Draw with the pixel value set to blue^magenta = 0xf^0x8 = 0x7 (^ is Xor). The funny thing is that you may never have allocated color cell 0x7. When you Xor draw with 0x7 over the blue 0xf background, the pixels are changed to magenta 0x8. ~chuck -- +--------------------+ Chuck Ocheret +---------------+ |chuck@fid.Morgan.COM| Morgan Stanley & Co., Inc. |(212) 703-4474 | | Duty now ... |19th Floor, 1251 Avenue of the Americas|for the future.| +--------------------+ New York, N.Y. 10020 USA +---------------+