MSACKS@IBM.COM (Michael Sacks) (05/09/89)
Fast Infinitely Undoable Graphics... Problem: An application requires the capability to display complex pictures ( > 1000 graphic primitives such as lines, polygons, text etc. ) in such a way that an arbitrary number of individual graphic primitives may be chronologically and quickly undone, one by one, all the way to the very first primitive drawn. The undoing process must occur with the same rapidity as the drawing process and be visible to the end user. In short we are faced with the problem that graphic operations while additive are not subtractive. The problem is how can I do this using Xlib. There are a number of possibilities, listed below, some of which have been implemented on other graphic systems( eg: suntools). However the client/server model in X poses unique design constraints in this problem. There are 3 obvious solutions: (1) Maintain a client data structure which is traversed for redisplay each time a primitive is undone. (2) Before each primitive is drawn, obtain and store in the client application the set of pixels that the primitive would would be written into, and on undoing restore these pixels effectively erasing the primitive. The pixels are stored in the application, and periodically compressed to conserve space. (3) Before each primitive is drawn, associate a set of Pixmaps in the server covering the pixels that the primitive would be drawn into, and on undoing, restore these pixmaps, effectively erasing the primitive. Comments on X solutions: (1) an obvious approach, but for large pictures is too inefficient. Consider picture with 1000 primitives and a conservative 5 bytes overhead to be sent to server per primitive drawing operation. To draw the complete picture requires 5 x 1000 bytes to be sent to server. To undo a graphics operation requires redrawing the whole picture and would cost on average 2500 bytes. However to undo the complete picture requires 5000 + 4995 + 4990 ....+ 10 + 5 = 2.5 Meg to be sent to server!. For fast undo of complex pictures this approach is impractical as time spent actually redrawing the whole picture is too great. (2) This approach previously implemented on Suntools. Worked very well and was quick, undoing was faster than doing!. Typically to save pixels under a line requred a number of 10 by 10 blocks of pixels, say 20 of them. Thus to undo each line element requires constant 2000 bytes associated with it. Undoing the total picture requires 2 meg of data to be saved, which after compression or run-length encoding could be easily reduced 50%. A graphic undo requires a constant 2000bytes to restore pixels. To undo complete picture requires 2Meg of data to be sent to server. Undoing is fast as the blocks of pixels get restored efficiently using pixblt operations. In X however, this requires creation and repeated transmision of Images accross network. (3) An X'ish approach. Store pixmaps on server, save pixmap id's in client and copy pixmaps back to window on undoing. Undoing primitive costs 5bytes to be sent to server and undo total picture requires 5k to be sent to server. While plausable in theory, how would current X servers handle the creation of 20,000 pixmaps? Any comments on this problem, similar experiences, alternative approaches, efficiency issues that I as an X novice may not be aware of. thanks in advance ... michael sacks
tmb@wheaties.ai.mit.edu (Thomas M. Breuel) (05/18/89)
Fast Infinitely Undoable Graphics... Problem: An application requires the capability to display complex pictures ( > 1000 graphic primitives such as lines, polygons, text etc. ) in such a way that an arbitrary number of individual graphic primitives may be chronologically and quickly undone, one by one, all the way to the very first primitive drawn. The undoing process must occur with the same rapidity as the drawing process and be visible to the end user. In short we are faced with the problem that graphic operations while additive are not subtractive. [... some solutions ...] There is yet another solution to your problem, in fact one which lets you undo graphics in arbitray order. Essentially you want to count for each pixel how often it has been drawn. Well, this is relatively straightforward to do with BITBLT: (1) allocate a number of bitmaps (say 10) on the server (2) when you draw a new item, draw it inside its own clean bitmap (3) consider the 10 bitmaps on the server bits of a counter; add "1" to the counter wherever your new item want to draw. You can do this using perhaps 4*10 BITBLT operations (you need another temporary bitmap for the carries). (4) OR together the 10 bitmaps and display the result If you want to undo, you subtract rather than add. On an Amiga, talking to the BLIT directly, this takes perhaps 100ms; a LIFE game that someone hacked up some time ago worked this way. I don't know how well X11 would deal with this. Thomas.
peter@ficc.uu.net (Peter da Silva) (05/19/89)
[keep a count of the number of times the bit has been set] This doesn't work if you ever draw anything with color 0 (i.e., erase). Let's say you draw a black square, and then erase a letter 'A' in the middle of it. What do you do with the bits you cleared? Either you leave the count alone (and have no record of the 'A'), or you decrement it (and have an inaccurate record of the resulting square). -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Business: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180. Personal: ...!texbell!sugar!peter, peter@sugar.hackercorp.com.
tmb@wheaties.ai.mit.edu (Thomas M. Breuel) (05/20/89)
In article <4243@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
[keep a count of the number of times the bit has been set]
This doesn't work if you ever draw anything with color 0 (i.e., erase).
Obviously. However, if you have a system that is built on the paradigm
of putting up individual "objects" on the screen such that you can
remove them or manipulate them individually, it doesn't even really
make sense just to draw a rectangle in the background color.
However, you can repeat the same trick of counting pixels for several
"layers" or several "colors" (with the obvious semantics of one layer
shadowing another).
peter@ficc.uu.net (Peter da Silva) (05/22/89)
In article <2532@wheat-chex.ai.mit.edu>, tmb@wheaties.ai.mit.edu (Thomas M. Breuel) writes: > In article <4243@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes: > > [keep a count of the number of times the bit has been set] > > This doesn't work if you ever draw anything with color 0 (i.e., erase). > Obviously. However, if you have a system that is built on the paradigm > of putting up individual "objects" on the screen such that you can > remove them or manipulate them individually, it doesn't even really > make sense just to draw a rectangle in the background color. Sure it does. Let's say you want to draw a circle with a square hole in it. How do you do this? You draw a circle and then you draw a square in the background color. So how do you undo the square? > However, you can repeat the same trick of counting pixels for several > "layers" or several "colors" (with the obvious semantics of one layer > shadowing another). Except that you lose ordering information, unless you do something like adding a new layer every time you change colors. This would probably save some space, but still wouldn't be able to deal with xor-mode drawing. That would require each xor-mode operation to be cut up into a separate color-1 and color-1 (or whatever pair of colors you select) operation... which would actually increase the memory required if you do a lot of xor-ing... not to mention slowing drawing down quite a bit. You might be able to save some space with a scheme like this. But not more, I think, than something more conventional like run-length-encoded deltas. -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Business: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180. Personal: ...!texbell!sugar!peter, peter@sugar.hackercorp.com.
madd@bu-cs.BU.EDU (Jim Frost) (06/05/89)
At the company I worked for just a few short months ago, we had the task of porting a very object-oriented graphical application to X Windows. Since the application was object-oriented, and the objects could be manipulated (scaled, moved, drawn, undrawn, etc), we had basically the problem you have. Since we were porting to a Sun X server, we had a tremendous incentive to make the resulting code be pretty efficient, and I think we did fairly well at that. What we did was keep a tree of objects. We had three kinds of objects: shapes, which were obvious primitives such as point, line, circle, rectangle, and text; objects, which were composed of shapes and which could be opaque or transparent, active ("touchable") or inactive, and some other properties; and surfaces, which were basically windows (but which had properties such as transparency, floatability, and "touchability" which are difficult to impossible to do under X) which could have either objects or shapes drawn on them. To get reasonable draw speeds, we did two things. First, we always drew on a pixmap rather than directly on the display window, with drawn areas copied in a single block to the window. X refresh requests could therefore be satisfied with merely a copy, which was a huge gain considering the complexity of the displays we were dealing with (50,000 shapes were not uncommon). Second, no drawing was done until an explicit or implicit refresh was done (implicit meant that an input routine was called, obviously requiring the display to be updated). A list of areas where the display needed to be updated was kept, and only those areas which were affected were ever redrawn. To keep things simple, anything that was in an affected area was redrawn whenever that area needed to be redrawn, and *only* those things were redrawn. There are many cases where you can loose a lot of performance that way (eg when adding things but not removing them), but we had limitations which caused me to leave it as it was. This technique was very successful, and turned out to be very portable as well. We moved the application from the X environment to the SGI GL environment in two days (it screamed on the SGIs). jim frost software tool & die madd@bu-it.bu.edu