Hi!
I’ve spent a few hours porting (old crappy) Object Pascal code into C"++" code,
and studying the SDL API. I have to dig deeper into the inner workings of SDL
before I can contribute any real code, but there are some ideas I’d like to
discuss.
First, I’d like to know if there’s any existing subsystem that could be used
(possibly extended), instead of implementing something new. What I have in mind
is basically a more flexible description of the screen than the current screen
surface. As an example, I’ll use the game I’m porting:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| ___________________________
| | |
| | |
| | |
| | |
| Main view | |
| | |
| | |
| | |
| | |
| |___________________________|
_|_ _ _ Splitscreen view_ _ _|_|
|___________________________|
The splitscreen gets it’s data from a single buffer of the same size as the
splitscreen window - no scrolling or double buffering.
The main view has 3 buffers that are 32 pixels wider and 32 pixel taller than
the main window. Hardware scrolling is used to avoid refreshing or scrolling
the entire buffers, and two buffers at a time are used to double buffer the
sprite rendering for flicker and tearing free animation. (However, this doesn’t
work on many modern, broken “VGA” cards - but that’s another story…)
(The next paragrapht is not really important here - I describe it just to
explain how a screen with just two tiles of scroll margin can deal with maps
of unlimited size.)
The third buffer of the main view is used for preparing new buffers for the
scrolling. While the display/back pair of buffers swap away, scrolling for 16
pixels (ie 16 video frames), the third buffer is refreshed a few tiles at a
time, so that it’s ready to replace the oldest buffer in the display/back pair
before it’s hardware scrolling margin is exhausted. Then the cycle starts
over, and another 16 frames later, the second buffer in the pair is replaced.
This way, the entire background scroller takes only about half the time of
rendering one 32x32 sprite, in the original VGA Mode-X implementation.
Now, to reimplement this efficiently, with or w/o hardware scrolling, one would
need
1a) A way to use VRAM buffers bigger than the screen.
2a) Hardware scrolling support
or
1b) A way to use buffers (mem or VRAM) bigger than the screen.
2b) Optimized VRAM->VRAM scrolling + partial updates.
and
3) A more evolved abstraction of the display than a single display
window, to deal with splitscreens and windows.
- and 2) are (probably) quite easy; allow buffers to be bigger than the actual
screen, and add XOffset and YOffset in some suitable place. (My game stores h/w
scroll offsets for each buffer, which makes sense considering that they are to
be applied when the buffers are flipped in, NOT when the offsets are changed.
That would correspond to having the scroll offset fields in the SDL_Surface
struct, but then again, the game doesn’t use it’s corresponding struct for
anything but display surfaces…)
As to hardware scrolling; when it’s supported, it’s just a matter of doing it -
the multi-buffering and updating works as usual.
When there is no hardware scrolling, it gets more complicated, though. The
simplest solution is probably to set up VRAM buffers of the same size as the
display, and then do in-place blit scrolls - with VRAM->VRAM DMA when
available. There will also have to be one oversized buffer for each real
display buffer (in VRAM or system memory): These are the buffers that the
application sees, and the buffers where SDL gets the areas that are exposed
when scrolling.
Ok; I can hardly follow the above myself, so here’s some more ASCII art,
describing how an oversized buffer is scrolled and “flipped” in on a target
without hardware scrolling support (only double buffering here):
____________ ____________
| | | |
| Currently | | Back |
| visible | | buffer | <== Real display buffers
| buffer | | |
| | | |
|____________| |____________|
________________ ________________
| | | |
| | | |
| Currently | | Oversize |
| "visible" | | back | <== "virtual" display buffers
| oversize | | buffer |
| buffer | | |
| | | |
|________________| |________________|
Now, we scroll the back buffer full right. This means that the scroll offset
for the corresponding oversize buffer changes, and that the real display buffer
has to be blit scrolled acordingly:
____________ ____________
| | |## |
| Currently | |## Back |
| visible | |## buffer | <== Real display buffers
| buffer | |## |
| | |## |
|| |##|
________________ ________________
| | | |
| | |++ |
| Currently | |++ Oversize |
| “visible” | |++ back | <== “virtual” display buffers
| oversize | |++ buffer |
| buffer | |++ |
| | |++ |
|| |_|
The ## area is now invalid (as the data that’s supposed to show up there isn’t
in the display buffer), and has to be reconstructed by blitting it in from the
oversize back buffer. (The ++ area is the source area.)
Now, we just do the usual double buffered flip, and there it is!
Finally, this splitscreen thing… Theoretically, the best abstraction I can
see right now is to make every part of the screen a separate Display Surface,
and then use some new structure to define how these relate to the physial
display.
As an example, my game display could be implemented using two SDL (Extended)
Display Surfaces set up like this:
SDL_Surface screen:
w = 352 //Surface size
h = 240
display_w = 320 //Display window size
display_h = 208
display_x = 16 //Offsets for the display window
display_y = 16
buffers = 3 //3 duffers. Does SDL support more than 2, actually...?
SDL_Surface dashboard;
w = 352 //(Must be same - VGA splitscreen does not change pitch)
h = 24
display_w = 320 //Display window size
display_h = 24
display_x = 0 //Offsets for the display window
display_y = 0 //(Cannot scroll, as VGA can only star a split screen at
// VRAM address 0.)
buffers = 1 //(VGA splitscreen can't be double buffered; See above.)
It may or may not be a good idea to attach the display size and offset stuff
to the surface struct; not sure. I do think that it belongs with the display
buffers though, as the timing is very critical for real hardware scrolling on
some hardware, so the Flip() function must have all info available.
Any ideas?
//David
…- M u C o S -------------------------. .- David Olofson --------.
| A Free/Open Source | | Audio Hacker |
| Plugin and Integration Standard | | Linux Advocate |
| for | | Open Source Advocate |
| Professional and Consumer | | Singer |
| Multimedia | | Songwriter |
-----> http://www.linuxdj.com/mucos -'
—> david at linuxdj.com -’