aperez@caribe.prime.com (Arturo Perez x6739) (04/11/90)
I'm working on some code from xtank (to get it to work in color) and I'm running into something I don't understand. Could some kind soul out there explain what's happening? I'm running the MIT X server, release 4 with patches 1-9 installed on a sun 3/60 whose default visual is PseudoColor. The xtank game creates scads of GC's, one for every combination color, operation, and font. That turns out to be about 100 GC's. There also seems to be quite a lot of bitmaps, possibly as many as 350. That's just for background. There are 2 modes of operation, GXxor and GXcopy. The GXxor operation is used for most of the drawing operations involving the bitmaps, in order to draw, erase, move, draw the bitmaps. Originally, the code looked like this: for(i = 0 ; i < MAX_COLORS ; i++) { for(j = 0 ; j < MAX_DRAW_FUNCS ; j++) { switch(j) { case DRAW_XOR: values.function = GXxor; values.background = vid->bg; values.foreground = vid->color[i] ^ vid->fg; And to draw a bitmap, like so: #define draw_picture(w,x,y,pic,func,_color) \ { \ int tmp_x = x - pic->offset_x; \ int tmp_y = y - pic->offset_y; \ if(x > -pic->offset_x && tmp_x < vid->win[w].width && \ y > -pic->offset_y && tmp_y < vid->win[w].height) { \ if(vid->planes == 1)\ XCopyArea(vid->dpy,vid->pixid[pic->pixmap],vid->win[w].id, \ vid->graph_gc[func][_color],0,0,pic->width,pic->height, \ tmp_x,tmp_y); \ else\ XCopyPlane(vid->dpy,vid->pixid[pic->pixmap],vid->win[w].id, \ vid->graph_gc[func][_color],0,0,pic->width,pic->height, \ tmp_x,tmp_y, 1);\ }\ } And that didn't work. All I got were white blocks instead of the bitmaps. Now, on a PseudoColor screen, this is obviously wrong because we're dealing with colormap entries, not pixel values. So, I changed it to this: for(i = 0 ; i < MAX_COLORS ; i++) { for(j = 0 ; j < MAX_DRAW_FUNCS ; j++) { switch(j) { case DRAW_XOR: values.function = GXxor; values.background = vid->bg; values.foreground = vid->color[i]; And that didn't work. The bitmaps came out correctly, but lines and text did not. The lines and text didn't come out at all, as a matter of fact. Also, in mono the bitmaps came out fine, but on a color screen the bitmaps came out in reverse, i.e. black on white, instead of white on black. This is background for my first bunch of questions. How come lines didn't come out when I`m using the GC for xor? All I'm doing is using it in an XDrawLine request. Why do the bitmaps come out as black on white on a color screen? So, next I try: for(i = 0 ; i < MAX_COLORS ; i++) { for(j = 0 ; j < MAX_DRAW_FUNCS ; j++) { switch(j) { case DRAW_XOR: values.function = GXxor; values.background = vid->color[i]; values.foreground = vid->bg; And that works perfectly in mono but in color the bitmaps come in in black with a colored box surrounding them. Why the difference? I would have thought that if the bitmap looked fine in mono, it should have looked fine in color as well. So, then I changed it to: for(i = 0 ; i < MAX_COLORS ; i++) { for(j = 0 ; j < MAX_DRAW_FUNCS ; j++) { switch(j) { case DRAW_XOR: values.function = GXxor; if (vid->color[i] == vid->fg) { values.background = vid->fg; values.foreground = vid->bg; } else { values.background = vid->fg; values.foreground = vid->color[i]; } And this sort of works for both color and black/white. At least, the bitmaps come out color on black and white on black. But, out of the set of colors Black, White, Red, Orange, Yellow, Green, Blue and Violet on my workstation (3/60 /dev/cgfour0) the orange comes out as dark blue and the blue and violet don't come out at all, that is, the bitmaps drawn in those 2 colors are invisible. Even worse, on other workstations (even other 3/60) none of the colors look correct. Why do the colors look right on my machine but no one else's? Why don`t the colors come out right if I XOR them onto black? I reason, probably incorrectly, that the colors are behaving as if they were being XOR'ed onto white. So, I change the draw_picture macro to #define draw_picture(w,x,y,pic,func,_color) \ { \ int tmp_x = x - pic->offset_x; \ int tmp_y = y - pic->offset_y; \ if(x > -pic->offset_x && tmp_x < vid->win[w].width && \ y > -pic->offset_y && tmp_y < vid->win[w].height) { \ if(vid->planes == 1)\ XCopyArea(vid->dpy,vid->pixid[pic->pixmap],vid->win[w].id, \ vid->graph_gc[func][_color],0,0,pic->width,pic->height, \ tmp_x,tmp_y); \ else\ switch(func) {\ case DRAW_XOR : \ if (_color != WHITE)\ XCopyPlane(vid->dpy,vid->pixid[pic->pixmap],vid->win[w].id,\ vid->graph_gc[func][WHITE],0,0,pic->width,pic->height, \ tmp_x,tmp_y, 1);\ case DRAW_COPY : \ XCopyPlane(vid->dpy,vid->pixid[pic->pixmap],vid->win[w].id, \ vid->graph_gc[func][_color],0,0,pic->width,pic->height, \ tmp_x,tmp_y, 1);\ }\ } \ } And everything looks correct, in both color and mono. And I've just converted the program into a real pig because CopyPlane has gotta be one of the most expensive Xlib calls. Why doesn't the vanilla XOR work? Is there a more efficient way to get the d****d bitmaps up on the screen in the correct color? Arturo Perez ComputerVision, a division of Prime aperez@cvbnet.prime.com Too much information, like a bullet through my brain -- The Police
joel@decwrl.dec.com (Joel McCormack) (04/13/90)
>And everything looks correct, in both color and mono. And I've just converted >the program into a real pig because CopyPlane has gotta be one of the most >expensive Xlib calls. I won't go into problems with XORing in color. It's ugly. However, on most modern X servers, your statement about CopyPlane is incorrect. If the server is careful, most hardware can paint faster using CopyPlane rather than CopyArea. For example, here's how many times per second you can perform a 500x500 CopyArea from 8-bit pixmap to 8-bit screen vs. 500x500 CopyPlane from 1-bit pixmap to 8-bit screen on various machines. (These are numbers I know have been achieved in one server or another; for any machine it may be that no single server achieves both numbers. I also know that the Sun cfb CopyPlane numbers are probably better with the current post-R4 server Keith Packard has.) Machine CopyArea CopyPlane ---------------------------------------------------------- DECStation 3100 20.0 38.0 DECStation 5000/200CX 38.8 59.1 Sun cfb 20.1 23.3 Sun GX 18.2 93.1 Newly announced machine with 1.4 10.0 really great graphics performance purchased from another company, both of which will remain anonymous. - Joel McCormack (decwrl!joel, joel@decwrl.dec.com)
keith@EXPO.LCS.MIT.EDU (Keith Packard) (04/13/90)
To use CopyPlane in XOR mode, you need to set up the fg and bg values in the GC so that the fg value will result in the desired color in the destination, while the bg value will not modify the existing bits. The bg value is simple, the only value which will leave the bits unmolested is 0. For the fg value, remember that XOR mode effectively inverts the destination bits which match the portions of the fg which are set, so choose the fg value so that it transforms the desination from the original background to the desired pixel value: Original desination: GC fg value: result: background ^ fg = color[i] A simple boolean exercise leaves fg = background ^ color[i] Or, in your original parlance: for(i = 0 ; i < MAX_COLORS ; i++) { for(j = 0 ; j < MAX_DRAW_FUNCS ; j++) { switch(j) { case DRAW_XOR: values.function = GXxor; values.background = 0; values.foreground = vid->color[i] ^ vid->bg; As an aside, your code had a special case for depth-1 images. Rest assured that the server performs CopyPlane using the same code as CopyArea when the destination is 1 bit deep, so you can replace that with: #define draw_picture(w,x,y,pic,func,_color) \ { \ int tmp_x = x - pic->offset_x; \ int tmp_y = y - pic->offset_y; \ if(x > -pic->offset_x && tmp_x < vid->win[w].width && \ y > -pic->offset_y && tmp_y < vid->win[w].height) { \ XCopyPlane(vid->dpy,vid->pixid[pic->pixmap],vid->win[w].id, \ vid->graph_gc[func][_color],0,0,pic->width,pic->height, \ tmp_x,tmp_y, 1);\ } \ }