[comp.windows.x] NEEDED: Color "OR" operation

gilgalad@caen.engin.umich.edu (Ralph Seguin) (05/15/91)

Hi.  I need the ability to specify a color dominance in graphics operations
in X.  More or less a graphics "OR" routine.  I need an efficient means
of doing this with XPutImage (I DO NOT want to copy back the pixmap section
and do the "OR" locally since that would involve multiple transfers, very
inefficient).  The situation is this:  I have a bitmap (1 plane pixmap)
locally, and I wish to place it onto a server (color or bw) and I want to
be able to specify this behavior:

source	dest	result
------	----	------
fg	fg	fg
fg	bg	fg
bg	fg	fg
bg	bg	bg

bg represents the background (or actually, any) color (index)
fg represents the foreground (or color to dominate) color (index)

As you can see, whenever either pixel is the foreground (or specified
dominant color), the result will be a foreground, ...
More or less an "OR" operation.

Is there some efficient means of implementing this?
Is there a way of mapping all pixels of a certain color within a region
to be another color (on the server)?
Is there a friendly way of allocating a color to be at indices 0 and 1
without screwing up the global color map?
Will R5 take care of this :) ?

			Thanks, Ralph

Ralph Seguin			rps@arbortext.com
536 South Forest Apt. #915	gilgalad@zip.eecs.umich.edu
Ann Arbor, MI 48104		(313) 662-4805

ekberg@asl.dl.nec.COM (Tom Ekberg) (05/15/91)

 > Hi.  I need the ability to specify a color dominance in graphics operations
 > in X.  More or less a graphics "OR" routine.  I need an efficient means
 > of doing this with XPutImage (I DO NOT want to copy back the pixmap section
 > and do the "OR" locally since that would involve multiple transfers, very
 > inefficient).  The situation is this:  I have a bitmap (1 plane pixmap)
 > locally, and I wish to place it onto a server (color or bw) and I want to
 > be able to specify this behavior:
 > 
 > source	dest	result
 > ------	----	------
 > fg		fg	fg
 > fg		bg	fg
 > bg		fg	fg
 > bg		bg	bg

One way to do this is to transfer the bitmap to a 1-bit deep pixmap on the
server via XPutImage, then use XCopyPlane putting the following into the
GContext for XCopyPlane: the foreground/background you want, and the 1-bit
pixmap as the clipping mask.  This will leave the pixels corresponding to 0's
in the pixmap alone and write the foreground for the pixels corresponding to
1's in the pixmap.

  -- tom, ekberg@asl.dl.nec.com (x3503)

mouse@lightning.mcrcim.mcgill.EDU (der Mouse) (05/16/91)

> I need the ability to specify a color dominance in graphics
> operations in X.  More or less a graphics "OR" routine.  I need an
> efficient means of doing this with XPutImage (I DO NOT want to copy
> back the pixmap section and do the "OR" locally since that would
> involve multiple transfers, very inefficient).  The situation is
> this:  I have a bitmap (1 plane pixmap) locally, and I wish to place
> it onto a server (color or bw) and I want to be able to specify this
> behavior:

> source  dest    result
> ------  ----    ------
> fg      fg      fg
> fg      bg      fg
> bg      fg      fg
> bg      bg      bg

I thought the source was only 1 bit deep...should the left column be 1s
and 0s perhaps?

> bg represents the background (or actually, any) color (index)
> fg represents the foreground (or color to dominate) color (index)

> Is there some efficient means of implementing this?

For arbitrary indices?  No; you need two copy calls in the general
case.  (Or, you need to use one of the tricks below, like the stipple
trick.)

If you are allocating the colors yourself, you need only two of them,
and your Visual is appropriate, you can use XAllocColorPlanes to
request one bitplane and one pixel, set the window's backing-pixel to
the pixel value and the backing-planes to the plane bitmask, then set
your GC's planemasks to write to only the plane in question, and
pretend you're on a monochrome server where you can get any effect you
want by using one of GXand, GXor, GXnand, or GXnor.

Another possibility is to set the GC's stipple to the bitmap, the
fill-style to FillStippled, the foreground to fg, and do a
FillRectangle operation.

Another possibility is to set the GC's clip-mask to the bitmap, the
foreground to fg, and do a FillRectangle; however, I *think* the MIT
server turns clip-masks into lists of rectangles, and if the picture
doesn't decompose nicely into rectangles this will (a) eat up server
memory and (b) draw comparatively slowly.  It will also cost some setup
time while the server scans the bitmap and sets up the rectangles.  And
what the MIT server does, many other servers pick up.  (I'm sure I'll
be corrected if I misread that code....)

> Is there a way of mapping all pixels of a certain color within a
> region to be another color (on the server)?

Not within the core protocol, at least without making assumptions about
the presence of other colors.

> Is there a friendly way of allocating a color to be at indices 0 and
> 1 without screwing up the global color map?

No.  But the AllocColorPlanes operation I outlined above will almost
always succeed, and it gives you most of the benefits you'd have if you
could ensure your colors were at 0 and 1.  (Assuming a dynamic visual.
You naturally will have to live with the color indices you get if you
have to use a static visual.)

> Will R5 take care of this :) ?

I'd be surprised if R5 changes anything bearing on my comments above,
except perhaps the bit about the (in)efficiency of clip-masks.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

mouse@lightning.mcrcim.mcgill.EDU (der Mouse) (05/16/91)

>> I need the ability to specify a color dominance in graphics
>> operations in X.  [...]

> and your Visual is appropriate, you can use XAllocColorPlanes to
...
> No.  But the AllocColorPlanes operation I outlined above will almost

Oops.  (I hate it when that happens.)

The AllocColorPlanes operation is for DirectColor visuals only.  For
PseudoColor (and GrayScale, if you want to deal with that) use
XAllocColorCells.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

mrm@nss1.com (Michael R. Miller) (05/17/91)

In article <1991May15.052219.26586@engin.umich.edu> gilgalad@caen.engin.umich.edu (Ralph Seguin) writes:
>Hi.  I need the ability to specify a color dominance in graphics operations
>in X.  More or less a graphics "OR" routine.  I need an efficient means
>of doing this with XPutImage (I DO NOT want to copy back the pixmap section
>and do the "OR" locally since that would involve multiple transfers, very
>inefficient).  The situation is this:  I have a bitmap (1 plane pixmap)
>locally, and I wish to place it onto a server (color or bw) and I want to
>be able to specify this behavior:
>
>source	dest	result
>------	----	------
>fg      fg      fg
>fg      bg      fg
>bg      fg      fg
>bg      bg      bg

	Assuming the dest is always made of fg or bg pixels ...  If not,
	you may have to do the multiple xfers.

>Is there some efficient means of implementing this?
>Is there a friendly way of allocating a color to be at indices 0 and 1
>without screwing up the global color map?

	Allocate your own colormap and associate it with a
	particular window (see XChangeWindowAttributes()).

	Your fillStyle will be OpaqueStipple or Stipple.
	
	For this to work you must obtain the correct visual first.
	Also you will need to deal with EnterLeave events and
	FocusIn/FocusOut events as well as the colormap events.
	Keep track of what map has been installed (similar to
	window manager code.  Look at twm or, if you have it,
	mwm) and where the cursor is.

	Caveat:  If your visual is of a static type, you may not
	be able to do this without the multiple xfers.  If you have
	multiple visuals, use the best one suited for your screen.
	Some B&W server screens especially will have static visuals
	where black is 0 and 1 is white (or vice versa).

	Your suggestion of using indices 0 and 1 is the easiest way 
	logically OR one color to another.  In your newly allocated
	but never used colormap, allocate your background color and
	then your foreground.  These should get pixels 0 and 1 (if
	not, use the kludge method and FORCE it; afterall it IS your
	colormap and no one else should use it).  Then when you want
	to do the OR operation, do just that.  A GCor operation will
	do what you want.

	If you have more than one pair of colors, you can do the same
	type of operation by setting the planemask appropriately.  The
	background is always an even numbered pixel and the foreground
	is odd.  The planemask is always 1 and the operation is GCset.
	Using GCclear with planemask 1 will go back to the background
	color.

>Is there a way of mapping all pixels of a certain color within a region
>to be another color (on the server)?

	Can we presume "region" to be a window?  If we can, the following
	will work ....

	To change all the pixels of one color to another, muck with the
	colors associated with the pixels in the colormap.  If all pixels
	numbered, say 5, are blue and you want them red, just store the
	color red at pixel 5's location.  The change should be immediate
	if that colormap is currently active or will be accomplished when
	the colormap is made active.

	If a "region" is not a window and cannot be made a window, there
	may be a way to do this (only in some cases where you have enough
	pixel values will this work).

	Use a different set of pixels initially filled with the same rgb
	values to populate the region.  The user will not be able to tell
	the difference until you alter that second set of pixels.  Slide
	the region around using GCclear on the old and GCset on the new
	region.  Change colors in the region by mucking the colormap.

	eg.  If the colormap has 16 entries and you want 8 colors, allocate
	each color twice.  The first set using pixels 0-7 and the second set
	pixels 8-15.  Pixels inside the region get populated with pixel
	values greater than 8 where as the rest of the window is populated
	with 0-7 valued pixels.  To change the colors of the region, you
	simply alter the pixel values 8-15.  If the region moves later on,
	simply GCclear with planemask 0x00000008 where the region currently
	exists and then GCset with the same planemask where the new region
	is to be drawn.  Use clip masks to draw unusually shaped regions.
	Make sure you either GCclear before changing the window contents or
	draw with the right pixel value as you change things.  GCclear is
	easier but may cause color changes your human user may find annoying.