New XBoard alpha

Discussion of chess software programming and technical issues.

Moderators: hgm, Dann Corbit, Harvey Williamson

User avatar
hgm
Posts: 27701
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

New XBoard alpha

Post by hgm »

For the adventurous:

I have been working on a new version of XBoard, abandoning the old graphics library of the X-toolkit, to replace it by the more modern 'cairo' graphics package. As a result in can now use anti-aliased png pieces, scale them to any size, render them with transparancy, etc. It has gotten to a stage where it seems to work reasonably.

The sources can be loaded as the latest snapshot from thecairo branch of my on-line repository. (To build, run ./autogen.sh befor ./configure!) The source tree comes with a png directory with anti-aliases 64x64 .png piece images.

When you set the -pgnDirectory to there (which can be done interactively in the View -> Board dialog), it will use the anti-aliased pieces. Otherwise it falls back on (scaled) 49x49 built-in pixmaps. In any case you can now size the board window by dragging it at a corner, similar to WinBoard.

I used the transparency with the entering of moves to exlude from analysis. If you are dragging a piece not for the purpose of doing that move, and analyse the subsequent position, but to exclude it from analysis of the current position, (because you grabbed it with a double-click), the dragged piece is rendered with transparancy (and an opaque piece is left on the from-square, as before), so that you are only pulling out its 'ghost', as it were.

Image
Michel
Posts: 2271
Joined: Mon Sep 29, 2008 1:50 am

Re: New XBoard alpha

Post by Michel »

Wonderful!

There was a recent discussion on the mailing list that xboard does some drawing which is not triggered by exposure events. This is something that is normally quite dangerous. As a result the gtk version was somewhat flaky (the animation at least).

Has this been fixed in the current version?
User avatar
hgm
Posts: 27701
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: New XBoard alpha

Post by hgm »

Well, I did not change any of that. Just replaced one brand of low-level drawing routines by another. And I must say that I still don't fully grasp the matter. If XBoard spontaneously wants to change the board (e.g. because the engine moved), how would I be able to trigger an expose event without drawing anything? This is still the Xt version, and it gives me expose events only when the window manager did something that necessitates a redraw. I don't see how it could work otherwise, because if redraw caused another expose event I would get into an infinite regression of expose events.

That the animation of the gtk version was so awful is at least partly because it uses a very poor algorithm. When you are dragging a piece, on every pointer-motion event it redraws the 4 squares that overlap the dragged piece in the old position to erase it, and then it draws the piece in the new position. But this creates the illusion of transparacy in the region where old and new piece overlap (which is almost the entire piece if you drag slowly, so it only moved a few pixels), as for a short time the original board will be displayed there. Erasing of the piece and then redawing it should have been done in a memory buffer, which is then copied to the screen after the new piece already covers the area behind it.

A second problem was the drawing of the grid: because cairo draws with ani-aliasing, you get a 2-pixel-wide transparent gray line when you ask for a 1-pixel-wide black line. Now in drawing the full board you would hardly notice, because the square-texture bitmaps were drawn after the grid, and wouldonly leave a 1-pixel space between them. But when the animation then was redrawing part of the board, the grid lines at the edge of that area would overwrite the square texture, and you would se the width of the line double in unexpected places. The same happened when the grid was redrawn to erase highlights, and to the highights itself. This was all easily cured by switching off anti-aliasing during the drawing of horizontal and vertical lines.

In this version everything works as smoothly as ever, but of course it still makes use of the Xt event system. No idea what would happen if we switched to another widget set. Perhaps nothing, because the gtk version did not only use cairo for drawing, but also gdk calls. Perhaps the problems arose from mixing those. This version is pure cairo (and I did never observe any ill effects from mixing Xt and cairo drawing, when I was gradually replacing oe by the other). So I have good hopes there wouldn't be any unexpected interaction between the widget set and the drawing code.

Anyway, switching to cairo removed an enormous amount of Xt-specific code from XBoard (all the XIM / XPM / bitmap stuff). There is now only very little left in xboard.c (only calls that have to do with timer interrupts and dispatching of input events, and of course the main Xt event loop). All the dialog handling is done by the GenericPopup in xoptions.c, and there already exists a gtk port of an earlier version of that. (I would just have to add listboxes, pop-down menus and interpretation of some extra formatting flags.) So it could be really easy to port the current version to gtk (or any other platform that supports cairo).
Michel
Posts: 2271
Joined: Mon Sep 29, 2008 1:50 am

Re: New XBoard alpha

Post by Michel »

how would I be able to trigger an expose event without drawing anything? This is still the Xt version, and it gives me expose events only when the window manager did something that necessitates a redraw. I don't see how it could work otherwise, because if redraw caused another expose event I would get into an infinite regression of expose events.
You need to invalidate the region you want to draw on. This will generate an expose event for the invalidated region and then you redraw the latter in the call back.

I don't know offhand what the the precise command is to invalidate a region in cairo (every toolkit has a different name for it) but I can try to find it.
Michel
Posts: 2271
Joined: Mon Sep 29, 2008 1:50 am

Re: New XBoard alpha

Post by Michel »

This is what is written here

http://developer.gnome.org/gtk/2.24/GtkDrawingArea.html

``Expose events are normally delivered when a drawing area first comes onscreen, or when it's covered by another window and then uncovered (exposed). You can also force an expose event by adding to the "damage region" of the drawing area's window; gtk_widget_queue_draw_area() and gdk_window_invalidate_rect() are equally good ways to do this. You'll then get an expose event for the invalid region.''
User avatar
hgm
Posts: 27701
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: New XBoard alpha

Post by hgm »

OK, that makes sense. But I still don't see the point. In a sense the expose event handler is also my own program. So whether I call DrawPosition() from the input event handler after updating the board, or let the input-event handler invalidate a region, which then triggers an expose event, which then calls DrawPosition(), it doesn't seem to make much of a difference. It just makes it more difficult to pass the relevant info to DrawPosition on what it should draw. (Currently DrawPosition remembers the board it has drawn in a private static copy, and when called with a NULL argument, as it is from the expose handler, just rdraws that. But that only works because there are also direct calls to DrawPosition which do specify a valid board.)

Actually it would be much better when all drawing took place outside the expose handler, but to a memory buffer rather than the display, so that the expose handler could simply copy that buffer to the screen. That would make it much simpler to copy only the part that was exposed (assuming the OS tells me what the damaged area was on a genuine expose event). In fact the code I just made does maintain such a copy, because the original animation code was reading information back from the screen to be able to restore it later (after the animated piece had evacuated the erea). And this proved 2-3 orders of magnitude slower in cairo than in the original Xt code (probably because each time I want to read a dozen or so pixels from the screen it converts the entire board image from Xt into cairo format). So I now draw everything static always both to the screen and the memory copy, so that I can read back from the copy to erase the animation piece. But this copy would be ideal as image source for expose events.

Also, generating system events for no other purpose than to call my own expose event handler also seems a pointless detour. If I want that handler to be called, I can simply call it myself. Or is the idea that events are queued, so that the redraw only starts after I am done with handling the current iput or timer event?
Michel
Posts: 2271
Joined: Mon Sep 29, 2008 1:50 am

Re: New XBoard alpha

Post by Michel »

Actually it would be much better when all drawing took place outside the expose handler, but to a memory buffer rather than the display, so that the expose handler could simply copy that buffer to the screen. That would make it much simpler to copy only the part that was exposed (assuming the OS tells me what the damaged area was on a genuine expose event). In fact the code I just made does maintain such a copy, because the original animation code was reading information back from the screen to be able to restore it later (after the animated piece had evacuated the erea). And this proved 2-3 orders of magnitude slower in cairo than in the original Xt code (probably because each time I want to read a dozen or so pixels from the screen it converts the entire board image from Xt into cairo format). So I now draw everything static always both to the screen and the memory copy, so that I can read back from the copy to erase the animation piece. But this copy would be ideal as image source for expose events.
Yes of course that is the best way to do it. You draw on a private copy and then the expose event handler just sends the relevant portion to the screen.
Also, generating system events for no other purpose than to call my own expose event handler also seems a pointless detour. If I want that handler to be called, I can simply call it myself. Or is the idea that events are queued, so that the redraw only starts after I am done with handling the current iput or timer event?
Well this is the way it always has been (also on windows/mac). The system relies on it being in control over the screen. If you invalidate this assumption then you are in dangerous territory. But it is perfectly possible to hide this. Toolkits do this. And it is also easy for a DrawingArea if you draw on a private buffer.

One reason of course is as you point out is that the system can bundle exposure events if too many arrive. Another is that if the invalid region happens to be covered then no expose event needs to be generated.

BTW. A notable exception to this design pattern seems to be OpenGL. Here the system gives you a buffer where you draw on as quickly as possible (not using exposure events). The graphics hardware makes sure this buffer somehow lands up on the screen.
User avatar
hgm
Posts: 27701
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: New XBoard alpha

Post by hgm »

Well, it should be fairly easy to change the code now to only draw to the backup (i.e. remove the direct drawing to the screen), replace it by such an invalidate_region call, and change the expose-event handler to draw to copy the backup bitmap in stead of initiating a draw.

Not sure whether it would be possible to efficiently invalidate an area for a very long diagonal arrow, or how the system would communicate to me what areas were exposed if it combines events.
Michel
Posts: 2271
Joined: Mon Sep 29, 2008 1:50 am

Re: New XBoard alpha

Post by Michel »

Not sure whether it would be possible to efficiently invalidate an area for a very long diagonal arrow
Well you could invalidate several small rectangles whose union contains the arrow. But it is probably not worth it.
or how the system would communicate to me what areas were exposed if it combines events.
It would not inform you. When you invalidate several rectangles in a row and the system decides to combine them it would simply generate an expose event for a rectangle containing the union of all the invalidated rectangles you supplied. Of course this would make animation jumpy, but it would only happen if you are trying to draw too quickly.

(BTW: perhaps GTK has more refined regions than just rectangles).
User avatar
hgm
Posts: 27701
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: New XBoard alpha

Post by hgm »

Well, I hope it is smart about combining events then. Because I'd rather redraw a1 and h8 in separate events rather than the whole board...