Re: Fixes for widescreen displays (Part 2: 3D)

Post tutorials on how to do certain tasks within game or engine code here.
Post Reply
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Fixes for widescreen displays (Part 2: 3D)

Post by mh »

mh wrote:OK, I posted parts of this one on QuakeSrc back in the day, but it didn't survive the Great Catastrophe, so here it is again in improved, debugged and 2008 form.

If you've ever played Quake on a widescreen display, you'll have noticed that while the width is correct, the top and bottom of the 3D views is cut off. You can obviously fix this by setting the value of the fov cvar to something higher (102 worked well for me), but you shouldn't have to. You'll also have noticed that the console, status bar pictures and menus are stretched. These two tutorials will resolve all of that.

The first one we're going to do is the 2D stuff, but before I even start anything...

BEGIN DISCLAIMER
Some people may feel that a wider FOV is cheating. I'm taking the viewpoint that as Quake lets you set the FOV anyway, there is no cheating involved, at least beyond what's possible with normal Quake. Server administrators should propose a protocol extension that requires servers to examine FOV settings and enforce them on clients if there are any bad feelings about this.
END DISCLAIMER
Here we go again. :D

This one is even easier than the last, as it all revolves around the SCR_CalcRefdef and CalcFov functions in gl_screen.c; so let's jump right in.

The first thing we do is replace CalcFov with these two:

Code: Select all

float SCR_CalcFovX (float fov_y, float width, float height)
{
	float   a;
	float   y;

	// bound, don't crash
	if (fov_y < 1) fov_y = 1;
	if (fov_y > 179) fov_y = 179;

	y = height / tan (fov_y / 360 * M_PI);

	a = atan (width / y);

    a = a * 360 / M_PI;

    return a;
}


float SCR_CalcFovY (float fov_x, float width, float height)
{
	float   a;
	float   x;

	// bound, don't crash
	if (fov_x < 1) fov_x = 1;
	if (fov_x > 179) fov_x = 179;

	x = width / tan (fov_x / 360 * M_PI);

	a = atan (height / x);

    a = a * 360 / M_PI;

    return a;
}
The second one (SCR_CalcFovY) is the exact same as the old CalcFov, but with the Sys_Error removed. If you look closely, you'll actually notice that both are the same function - you just flip width and height - but I prefer to keep them separate so that it's more obvious what's going on.

Speaking of obvious, all we're doing here is calculating an X FOV from a given Y FOV and vice-versa.

Now we need to actually use them, so pop this code into SCR_CalcRefdef. Again, I've given the line just before and after so you'll know where to insert it:

Code: Select all

	r_refdef.fov_x = scr_fov.value;

	// calculate y fov as if the screen was 640 x 432; this ensures that the top and bottom
	// don't get clipped off if we have a widescreen display
	r_refdef.fov_y = SCR_CalcFovY (r_refdef.fov_x, 640, 432);

	// now recalculate fov_x so that it's correctly proportioned for fov_y
	r_refdef.fov_x = SCR_CalcFovX (r_refdef.fov_y, r_refdef.vrect.width, r_refdef.vrect.height);

	scr_vrect = r_refdef.vrect;
That's literally it. We calculate the y fov (which is used for our projection matrix and frustum culling) as if the screen was 640 x 432, which seems as bit weird (why not 480?), but was chosen as Quake's "intended aspect ratio" (i.e. running at 640 x 480 with a full status bar showing), thus ensuring that we get a consistent vertical field of view, irrespective of the screen's resolution. Then we recalculate the horizontal field of view to get the extra stuff at the sides.

This code, by the way, will work for any aspect ratio - there's no need to check for a widescreen display aspect as part of it. However, you might notice that if you have a display that's narrower than 4:3 you'll start losing stuff at the sides. Fortunately, this is rarer, and even at the only common resolution it affects (1280 x 1024) there's no dramatic loss.

We really should fix that too, though, but that's a project for another day!
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

There's a part 3 to come here, by the way - fixing what happens when you play at a fullscreen resolution that's not the same aspect as your monitor. :D
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Team Xlink
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Post by Team Xlink »

mh wrote:There's a part 3 to come here, by the way - fixing what happens when you play at a fullscreen resolution that's not the same aspect as your monitor. :D
This set has been very useful, but I cannot find part 3.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

I can't even remember if I ever did it! :lol:
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Post Reply