On Aspect Ratios and OpenGL
Posted: Sun Aug 24, 2003 8:43 am
I've been trying to run Exult on my 17" PowerBook and there have been a few things bothering me... so I decided to fix them.
First, I want the game to fill my entire display, not just a portion of it. Since
my PowerBook has a wide-screen 1440x900 LCD display (8:5 aspect ratio), I had to add support for this myself. Instead of having Exult render a 4:3 game at 320x200, I needed to make it render a 8:5 game, so I widened it to 384x200. (320 * 8:5 / 4:3 = 384)
Second, the game uses non-square pixels, so when it is displayed anywhere other than full-screen 320x200 or 640x400, it is distorted--everything is stretched horizontally. The game has a 6:5 pixel aspect ratio, meaning that the pixels are taller than they are wide. This comes from the original game's 320x200 resolution being displayed on a 4:3 monitor. Nearly everything these days uses square pixels, so the game cannot be simply blitted pixel-for-pixel to the screen without distortion.
Third, I really like the Scale2x scaler. It works very well with the low-res cartoon-ish graphics in U7--much better, IMHO, than any continuous-tone rescaler like bilinear. This brings my 384x200 game up to 768x400. Now that is an odd resolution which you are very unlikely to find supported by any graphics hardware. In addition, when you have an LCD display, it is vastly preferable to work in its native resolution (1440x900 in my case.) So this will require a second rescale.
Forth, I did a few performance profiles and found that most of the time was being spent doing conversion from 8bpp to 32bpp. Why waste time there when my graphics card is perfectly capable of doing it for me?
Fifth, I noticed various screen-update problems when walking through visually-noisy areas such as the swamps. I might was well address this while I'm at it.
So... here's my solution:
Let the user specify a screen resolution independent from their game resolution:
384
200
2
Scale2x
1440
900
All of the scaler code remains as is, except, when they create a surface to draw into, they get an off-screen buffer instead of on-screen video memory. When the scalers are done, they call my update_rect() instead of SDL_UpdateRect(). In this function, I use OpenGL to draw the entire scaled 8-bit image to the screen at the resolution specified above. (Currently, this only works if the hardware supports the "EXT_paletted_texture" OpenGL extension)
This change has the side-effect of creating different coordinate systems between the display/mouse and the game. I addressed this by funneling all mouse-coordinate code through a single method (gwin->get_mouse_position) which does the mapping between game and screen resolutions.
It works beautifully, filling the whole wide-screen, not distorted, no update problems. This patch could also be used in windowed mode to compensate for the non-square pixels: set game to 320x200, scaled up to 640x400 and displayed properly at 640x480 (4:3).
Here's a screen shot: http://www.earthtribe.net/sean/dav/Scale2x-OpenGL.jpg
It's a 1440x900 JPEG (300KB)
I'm going now to submit the patches to source forge (This is my first contribution to an open-source project, so bear with me while I figure out how patches work).
First, I want the game to fill my entire display, not just a portion of it. Since
my PowerBook has a wide-screen 1440x900 LCD display (8:5 aspect ratio), I had to add support for this myself. Instead of having Exult render a 4:3 game at 320x200, I needed to make it render a 8:5 game, so I widened it to 384x200. (320 * 8:5 / 4:3 = 384)
Second, the game uses non-square pixels, so when it is displayed anywhere other than full-screen 320x200 or 640x400, it is distorted--everything is stretched horizontally. The game has a 6:5 pixel aspect ratio, meaning that the pixels are taller than they are wide. This comes from the original game's 320x200 resolution being displayed on a 4:3 monitor. Nearly everything these days uses square pixels, so the game cannot be simply blitted pixel-for-pixel to the screen without distortion.
Third, I really like the Scale2x scaler. It works very well with the low-res cartoon-ish graphics in U7--much better, IMHO, than any continuous-tone rescaler like bilinear. This brings my 384x200 game up to 768x400. Now that is an odd resolution which you are very unlikely to find supported by any graphics hardware. In addition, when you have an LCD display, it is vastly preferable to work in its native resolution (1440x900 in my case.) So this will require a second rescale.
Forth, I did a few performance profiles and found that most of the time was being spent doing conversion from 8bpp to 32bpp. Why waste time there when my graphics card is perfectly capable of doing it for me?
Fifth, I noticed various screen-update problems when walking through visually-noisy areas such as the swamps. I might was well address this while I'm at it.
So... here's my solution:
Let the user specify a screen resolution independent from their game resolution:
384
200
2
Scale2x
1440
900
All of the scaler code remains as is, except, when they create a surface to draw into, they get an off-screen buffer instead of on-screen video memory. When the scalers are done, they call my update_rect() instead of SDL_UpdateRect(). In this function, I use OpenGL to draw the entire scaled 8-bit image to the screen at the resolution specified above. (Currently, this only works if the hardware supports the "EXT_paletted_texture" OpenGL extension)
This change has the side-effect of creating different coordinate systems between the display/mouse and the game. I addressed this by funneling all mouse-coordinate code through a single method (gwin->get_mouse_position) which does the mapping between game and screen resolutions.
It works beautifully, filling the whole wide-screen, not distorted, no update problems. This patch could also be used in windowed mode to compensate for the non-square pixels: set game to 320x200, scaled up to 640x400 and displayed properly at 640x480 (4:3).
Here's a screen shot: http://www.earthtribe.net/sean/dav/Scale2x-OpenGL.jpg
It's a 1440x900 JPEG (300KB)
I'm going now to submit the patches to source forge (This is my first contribution to an open-source project, so bear with me while I figure out how patches work).