Complete.Org: Mailing Lists: Archives: freeciv-dev: May 2003:
[Freeciv-Dev] Re: (PR#4289) Pixel scroller

[Freeciv-Dev] Re: (PR#4289) Pixel scroller

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] Re: (PR#4289) Pixel scroller
From: "a-l@xxxxxxx" <a-l@xxxxxxx>
Date: Sat, 24 May 2003 09:30:43 -0700
Reply-to: rt@xxxxxxxxxxxxxx

To make a proper scroller, the backing store must be expanded with
one tile row on each side and one column above and underneath. I call
this the primary buffer. The canvas gets two pixel offset variables.
Set up a gdk timer that writes from the backing store to the screen
around 60 times pr sec. This is like the simplest of blitter
operations, using only the offsets (referred to as dither offsets in
GTK2), and will be relatively fast. Since the backing store is now
bigger than the display window, we can scroll up to
+-NORMAL_TILE_WIDTH and +-NORMAL_TILE_HEIGHT pixels along the axis,
only by adjusting the offsets, map_pixel_xy.

When that limit is exceeded, parts of the backing store can be
recycled, and only the fringes need updating ["update" =
put_tile(_iso), which is slow]. One of the attached images was posted
earlier by Jason, and describes partial redrawing. When recentering
with the mouse, the reusable area can be 25%-50%, but it's more like
85% when scrolling.

If anyone would want to use the scrolling, it'll have to be smooth.
The framerate of maximum 60 is to make sure that we at least don't
try to update video memory faster than the actual hardware drawing. If
the geniuses at MIT had at least allowed reading the position of the
cathode ray in the monitor, the whole situation would be easier, but
this will be only for a native win32 client using DirectX. The
problem with the above buffering method is that you'll get jittering
at every update, since the timer operations of gdk and the like
counts from the end of the last call, and the duration of this call
depends upon how much load it must process.

So I made a secondary buffer outside the primary, divided into four
subsections; Top, Bottom, Left, Right. Now say the player starts
scrolling NorthWest by moving the mouse to the upper left corner of
the window. We anticipate that 3 jobs will soon be required: recycling
the backing store, which is a large but dumb blit, updating Top, and
updating Left. Since we know this in advance, our timer can try to do
them one at the time, distributing the load over 3 different intervals.
Without this system, the scroller could halt suddenly at every tile
size pixel interval, and then continue smoothly until the next. That's
very annoying. At scrolling speeds larger than 1 tile pr frame, we
need to revert to the first method. But in my experience it's hard to
simulate smoothness at these speeds without reading the monitor
retrace anyway. And I think super fast scrolling will rarely be
desired, if ever.

Since there's a regular timer in place, I call it the graphics
handler. It is very suitable for other types of animation as well.
They could write to the backing store or to the window. Combat
animation, for example, should no longer freeze the client in any way,
I think. To avoid excessive drawing, it seems like a good idea to have
a layered drawing system, with terrain and units in different layers.
Maybe someone would want to animate the whale, or the fish, and it
could be independent from units drawn on the same tile.

There are some implications:
- Since the backing store must be bigger than the display window, many
existing functions are affected. map_to_canvas_pos() should probably
return whether the position is within the backing store, since
put_tile() depends on it to decide whether to redraw. That means
tile_on_border_canvas() needs adjustment, since it's used for

- After reading the mouse pointers position, the canvas coordinates
must be adjusted to point to the backing store:
  backing_x = screen_x + map_pixel_x + 2 * NORMAL_TILE_WIDTH;
  backing_y = screen_y + map_pixel_y + 2 * NORMAL_TILE_HEIGHT;

Hm, I think that's it.


PNG image

PNG image

[Prev in Thread] Current Thread [Next in Thread]