Sunday, 7th February 2010
Having tweaked the stereoscopic rendering code in Quake, I decided to have a go at Quake II. This doesn't natively support row-interleaved stereoscopic rendering, but I thought that the shared code base of Quake and Quake II should make extending Quake II relatively simple.
Quake II does have two console variables dedicated to stereoscopic rendering already, cl_stereo (enable/disable stereoscopic rendering) and cl_stereo_separation (controls the displacement of the camera between eyes; the same as LCD_X in Quake). These variables only seem to be used in the OpenGL renderer, though I haven't been able to get them to do anything meaningful – I have a hunch that you need a video card that supports stereoscopic rendering; these do exist, and have a socket on them for 3D glasses, but I'm having to make do with my DIY hardware. Furthermore, I've always found the OpenGL rendering in Quake and Quake II incredibly ugly, with blurry low-resolution textures (this is the reason I opted to emulate the software renderer when writing my own implementation of the Quake engine).
It turns out that Quake II does indeed render each frame twice with the camera offset when cl_stereo is switched on, but the software renderer doesn't do anything to blend the two views together. Using the same tricks as Quake – halving the height of the viewport, doubling the apparent stride of the render surface, shunting the address of the buffer down one scanline for one eye – seems to have done the trick, though finding out when exactly to carry out these steps hasn't been all that smooth. The particle rendering code still crashes with an access violation if called twice during a frame, but only in release mode. Fortunately, the entire software renderer has been written in C and assembly, so I've reverted to the C-based particle renderer instead of the assembly one for the time being as that doesn't appear to be affected by the same bug.
A slightly more bothersome problem is the use of 8-bit DirectDraw modes for full-screen rendering. Unfortunately, Windows seems to like interfering with the palette resulting in rather hideous colours. Typing vid_restart a few times into the console may eventually fix the issue, but it's far from an ideal solution. An alternative may be to rewrite the code to output 32-bit colour; this would also allow for coloured lighting. Unfortunately, I don't think I'd be especially good at rewriting the reams of x86 assembly required to implement such a fix, and the C software renderer I previously mentioned results in a slightly choppy framerate at high resolutions.
An alternative would be to learn how to use Direct3D from C and rewrite the renderer entirely, taking advantage of hardware acceleration but this would seem like an equally daunting task. If anyone has any suggestions or recommendations I'd be interested to hear them!