Inside3D!
     

Extending Quake Limits - Part 2: efrags

 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Programming Tutorials
View previous topic :: View next topic  
Author Message
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Fri Jan 08, 2010 6:09 pm    Post subject: Extending Quake Limits - Part 2: efrags Reply with quote

For part 2 of our series we're going to remove the limit on the number of efrags. This is a required step for part 1 (static entities) as static entities will use efrags, so with unlimited static entities we're going to run out of efrags quite soon.

Concept

What's an efrag? At the most basic level it's just a marker that an entity (either static or not) is currently inhabiting a certain leaf in the world. GLQuake uses them for just static entities whereas software Quake uses them for both types.

The default efrags limit is a piddling 640, and we're going to go through the roof here and get rid of it entirely.

This code will work with both software and GLQuake.

The code

Before we start writing any code, the differences in the two engines means that there are two different code files that handle efrags: gl_refrag.c for GLQuake and r_efrag.c for software Quake. Look at the two files, observe that there's only fairly minor differences between them, observe that the additional code in r_efrag.c has no impact whatsoever on GLQuake.

You could just use r_efrag.c for both, or you could keep them separate if you wish, or you may only maintain one of software or GLQuake. It's entirely up to you, but the code changes are identical for both versions.

On to the code. Open up your chosen efrags file and add this at the top:

Code:
// mh - extended efrags - begin
#define EXTRA_EFRAGS   32

void R_GetMoreEfrags (void)
{
   int i;

   cl.free_efrags = (efrag_t *) Hunk_Alloc (EXTRA_EFRAGS * sizeof (efrag_t));

   for (i = 0; i < EXTRA_EFRAGS - 1; i++)
      cl.free_efrags[i].entnext = &cl.free_efrags[i + 1];

   cl.free_efrags[i].entnext = NULL;
}
// mh - extended efrags - end


Now look for the R_SplitEntityOnNode function, look for the block that begins with "if (!ef)", and replace the contents of that block with this:
Code:
      if (!ef)
      {
         // mh - extended efrags - begin
         R_GetMoreEfrags ();
         ef = cl.free_efrags;
         // mh - extended efrags - end
      }


And that's all that's required. What's going on here is that we're actually keeping the original MAX_EFRAGS array as an initial block that's set up when the client starts. If that block gets exhausted we'll just allocate some more. The extra amount doesn't really matter, I just chose 32 so that we don't have potentially lots of runtime memory allocations and also so that we're not wasting memory by allocating too many. Once again it comes off the hunk so it's automatically released between map loads.

What's really nice about this extension is that it can quite easily be tested by setting your value of MAX_EFRAGS to something like 2, adding a Con_Printf to R_GetMoreEfrags, and just running a map.

Cleaning up

There's not much to be done here to be honest. You might like to change the name of MAX_EFRAGS to something like INITIAL_EFRAGS and maybe even reduce it's value (so that you're not wasting memory on efrags you may not need), or you might like to remove it entirely, set cl.free_efrags to NULL (instead of to cl_efrags) in your CL_ClearState function, and let R_GetMoreEfrags do all the work.

I would have constructed this tutorial around the last way but I like to keep all code-changes in a single file if at all possible.

A Note on Memory Usage

With both this tutorial and with my previous one we're allocating extra objects off the Hunk which will put some pressure on the memory Quake has available to run in. You should either increase the default heapsize a little or use my Quake Memory Manager tutorials (or similar) to avoid any issues from this.

The bottom line though is that the memory for the extra objects has to come from somewhere, and the Hunk is convenient as it is cleared automatically between map loads and will handle error checking for us.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
metlslime



Joined: 05 Feb 2008
Posts: 177

PostPosted: Fri Jan 08, 2010 9:55 pm    Post subject: Reply with quote

I was under the impression, when i last went through this code, that you could get rid of efrags entirely and just do client-side PVS checks for each static entity whenever the camera crossed a leaf boundary. That would simplify the code with a negligible performance hit.

On the other hand, I realize this tutorial is for software mode too, so you actually still need the efrags in that case.
Back to top
View user's profile Send private message
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Fri Jan 08, 2010 10:43 pm    Post subject: Reply with quote

metlslime wrote:
I was under the impression, when i last went through this code, that you could get rid of efrags entirely and just do client-side PVS checks for each static entity whenever the camera crossed a leaf boundary. That would simplify the code with a negligible performance hit.

On the other hand, I realize this tutorial is for software mode too, so you actually still need the efrags in that case.

Quite correct in both cases. Very Happy

The approach I use is to store a list of static entities in each leaf that each such entity touches, and if the leaf is in the PVS then so are all of the statics in it.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
reckless



Joined: 24 Jan 2008
Posts: 390
Location: inside tha debugger

PostPosted: Sat Jan 09, 2010 11:18 pm    Post subject: Reply with quote

i believe tochris also uses a different approach for efrags as the code is completly missing ?

instead theres a pvs calculating function in gl_rmain.

tbh if someone was to go about creating an engine from scratch (allmost) tochris might be a very nice starting point. the differences to normal quake
might be a little hard to cope with unless you have a lot of experience though.

mainly the client / server model of the code.

on the good side it includes the software renderer for those who require this still.
Back to top
View user's profile Send private message
dreadlorde



Joined: 24 Nov 2009
Posts: 86

PostPosted: Thu Feb 18, 2010 3:36 pm    Post subject: Reply with quote

I'm having trouble with this, when I compile this with gcc-4.3.3, I get this error
Code:

home/jake/src/proj/quake-git/r_efrag.c
/home/jake/src/proj/quake-git/r_efrag.c: In function ‘R_GetMoreEfrags’:
/home/jake/src/proj/quake-git/r_efrag.c:16: error: incompatible types in assignment
make[1]: *** [release/x11/r_efrag.o] Error 1
make[1]: Leaving directory `/home/jake/tmp/quake-git'
make: *** [release] Error 2

Where line 16 is
Code:

cl.free_efrags[i].entnext[i] = NULL;

I'm not sure what to do. Confused
_________________
Ken Thompson wrote:
One of my most productive days was throwing away 1000 lines of code.

Get off my lawn!
Back to top
View user's profile Send private message AIM Address
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Thu Feb 18, 2010 4:37 pm    Post subject: Reply with quote

It should be:
Code:
cl.free_efrags[i].entnext = NULL;

Note the lack of an "[i]" after "entnext".
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
dreadlorde



Joined: 24 Nov 2009
Posts: 86

PostPosted: Thu Feb 18, 2010 5:20 pm    Post subject: Reply with quote

mh wrote:
It should be:
Code:
cl.free_efrags[i].entnext = NULL;

Note the lack of an "[i]" after "entnext".

Doh!

You changed it when I wasn't here!! Wink Laughing
_________________
Ken Thompson wrote:
One of my most productive days was throwing away 1000 lines of code.

Get off my lawn!
Back to top
View user's profile Send private message AIM Address
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Programming Tutorials All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group