Tutorial *29*

There are many different ways to code something, and the first part of this tutorial is my own code, but MrG submitted an alternative method to displaying the fps. Both methods work fine, mine is more code, but offers a little more control over the display, while MrG's is smaller. It's up to you to decide which one to follow. Note that i've changed the cvar name in my version, for compability's sake.


One important thing missing in q2 is, in my opinion, a frames per second counter. So that's what this tutorial is about. The quake2 source is not much different from the Quake1 source, so basicly we need to do three thing:

-make a cvar to switch the fps counter on or off
-a function that calculates the fps and shows it
-check if the cvar is on or off

first, we'll create the cvar. Since the cvar should be accessable by all renderers (software/gl), we add the cvar to the main executable. To select the main executable (in visual c), go to build, "Set active configuration" and select "Quake2 - win32 Release" (or debug). Now find the cl_scrn.c file in the Source Files.


Scroll down a bit and find the cvar_t list. After this list, add:


cvar_t		*cl_drawfps;

This will create a cvar called cl_drawfps. As you might have figured, it doesn't do much at the moment. What we'll need to do is find a way to set a (default) value to it. Find the SCR_Init function and add



	cl_drawfps = Cvar_Get ("cl_drawfps", "0", CVAR_ARCHIVE);

after the other cvars. What this does is registering the "cl_drawfps" cvar in game. Setting it default to zero (the "0"). The CVAR_ARCHIVE is a constant (a variable with a fixed value), and means that the value set by the user will be saved to the config files. So if you use "cl_drawfps 1" in the game, this will be saved to the config file, and reloaded when you start the engine again. Other values here that are possible:

-CVAR_USERINFO - changes will be saved to the user config
-CVAR_SERVERINFO - changes will be saved to the server config
-CVAR_NOSET - changes cannot be made from the console, but only from the command line
-CVAR_LATCH - changes will be saved until the server is restarted

So now we have a cvar, but it isn't doing anything exciting yet. We'll leave it like that for now. First let's create the function that calculates the FPS and prints it to the screen. Let's call it SCR_showFPS, but first a little story on how to calculate the FPS. Basicly you need the the time it took to render one frame. To do this you get the current time and compare it to the last time you requested the time. Confusing huh? example:

-the time is 17:32:12 now
-at this moment the time is 17:32:20 (i'm a slow typer, mkay?)
the difference is 8 seconds
so if I typed this realtime onto your screen the frames (difference between the above two lines) would have been 1/8 fps.

Hope that clears it up a bit. Now we go back to the code.
Quake2 stores it's time as integers, which means we can't have floating point numbers (well, actually you can convert it, but that's not part of this tutorial). The function to get the current time is Sys_Milliseconds();. So we create three integers, one static (which remembers it's last value) and the other two are normal integers (one to save the currentime in, the other to save the fps in). So the structure we would get is like this:



static int currenttime;

int newtime, calc;



newtime = Sys_Milliseconds();

calc = (1000 / (newtime-currenttime) );

currenttime = newtime;

As you can see the 1 is replaced by 1000 because the Sys_Milliseconds returns milluseconds (well duh) instead of seconds. All we need to do next is print the calc value to the screen. But as this function is called every frame, the fps would be hardly readable on a fast system. That's why we "only" print it ten times per second. Thus the final version of our new function should look like this:



/*

================

SCR_showFPS

================

*/

int	fpscounter; // integer so we can check the last time the fps is updated

char	temp[32]; // temporary char where we store our fps string



void SCR_showFPS(void)

{

	static int currtime;

	int	newtime, calc;



	if ((cl.time + 1000) < fpscounter) // check if client time + 1000 is smaller then fpscounter

	{

		fpscounter = cl.time + 100; // yes, set fpscounter + 100

	}



	newtime		= Sys_Milliseconds(); // get the curren time



	if(newtime == currtime) // check if newtime is the same as currtime

		return; // yes, return to avoid a devide by zero error



	calc		= (int) (1000/ (newtime - currtime)); // calculate fps with the time from the last frame

	currtime	= newtime; // set the "last frame time" as current time



	if (cl.time > fpscounter) // check if the client time is greater then the fpscounter

	{

		Com_sprintf(temp, sizeof(temp), "%3i FPS\n", calc); // if so, update the temp char with the latest FPS value

		fpscounter = cl.time + 100; // also set the fpscounter + 100

	}



	DrawString(viddef.width - 64, 0 , temp); // draw the string to the screen, the upper right corner minus 64 pixels



}

As you can see the two if structures makes the fps update at only 1/10 of a second. If you still want to draw it every frame, comment the two if statements out and voila... your fps counter updates every frame. Now that's a lot code, luckely there's a variable which already contains the time it took to render the last frame (thanks to MrG for pointing that out to me); cls.frametime. So basicly we could delete the entire section where the frame time is calculated and replace it with the cls.frametime variable. The new code will look like this:



/*

================

SCR_showFPS

================

*/

int		fpscounter;

char		temp[32];



void SCR_showFPS(void)

{

	int calc;



	if ((cl.time + 1000) < fpscounter)

		fpscounter = cl.time + 100;



	if (cl.time > fpscounter)

	{

		Com_sprintf(temp, sizeof(temp),"%3.0ffps", 1/cls.frametime);

		fpscounter = cl.time + 100;

	}

	DrawString(viddef.width - 64, 0 , temp);

}

You should put that function somewhere above the SCR_UpdateScreen function.

Now the last thing to do is to check if the cl_drawfps cvar is set to true and then call the function we just created. To do this, go to the end of gl_scrn.c and have a look at SCR_UpdateScreen. As the comments say, this function is called every frame, so a perfect function to put our counter into. Let's try that. Scroll down to the end of the function and after



SCR_DrawLoading ();

add this:


			if(cl_drawfps->value)

			{

				SCR_showFPS();

			}

what does does is checking for the value of our cvar, and if it's set to true (1), it executes our SCR_showFPS function.


Now MrG's method. He basicly does the same as me, with the only exception being the cap on the drawing. So his version get's updated every frame. It's your call to choose which one you like.

Author: MrG

Some people have had troubles with getting Brams FPS display tutorial to work, so after I wrote my own fps display I was asked to write up a tutorial on it. Without further small-talk, let the tutorial begin.

This tutorial takes place within the Quake2 executable source, just so nobody opens up the wrong project and complains. :)

First things first, we are going to declare our cvar variable and then register it with the engine itself so that it can actually be used. This takes place in the file 'cl_main.c', so open that up.

At the top of the file we see a lot of other cvars being declared. This is where we are going to declare our variable for controlling whether the framerate is shown or not. The code we need to add in here is:



cvar_t	*cl_drawfps; // FPS Display - MrG

Now move further down the file and find the function named 'CL_InitLocal'. This is the function that we are going to use to register our cvar variable with the engine itself. Find the lind that reads:



cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);

Now add the following code directly below it.


cl_drawfps = Cvar_Get("cl_drawfps","0",CVAR_ARCHIVE); // FPS display - MrG

This tells the Quake2 engine that we wish to register a cvar with it, accessible by the name 'cl_drawfps', has a default value of 0, and has its value saved to the config file.

We are finished with that file now, and shall move onto the only other file we need to make some changes to, 'cl_scrn.c'. Find the function named 'SCR_UpdateScreen', we are going to make an external variable declaration to our cl_drawfps variable immediately above it.



extern cvar_t *cl_drawfps; // FPS display - MrG

Now we are moving into that function. Find the line that reads:


SCR_CheckDrawCenterString ();

Directly below this we are going to check the value of our cvar to see whether or not we are going to draw the FPS to the screen. If we are, we do a little math. The 'cls.frametime' variable holds the number of seconds that it has taken to render the previous frame. Without too much effort we can figure out that if we divide 1 by this number, we have our framerate (1/0.5 = 2fps, 1/0.01 = 100fps, etc). Insert the following code into the function.



// Draw FPS display - MrG

if (cl_drawfps->value) {

	char s[8];

	sprintf(s,"%3.0ffps", 1/cls.frametime);

	DrawString(viddef.width-64,0,s);

}

That does it for the coding. Compile it and load up Quake2. Now type 'cl_drawfps 1' at the console to enable the fps display. Enjoy :)



 
Not logged in
Sign up
Login:
Passwd: