Tutorial *33*

While browsing through the Quake 2 source code, sometimes you can get lucky and find a fully functional piece of code that Id Software disabled for some reason during the coding phase. Most code that is disabled was disabled because it was either used only in the debugging phase or they couldn't get it to work. Today, we'll be focusing on one such block; the block that draws alias model bounding boxes! Without further lengthy explanation, let's proceed....

Open the file ref_gl/gl_mesh.c, and go to the function R_DrawAliasModel. Scroll down until you see (my version may be cleaner than yours):



#if 0

qglDisable(GL_CULL_FACE);

qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

qglDisable(GL_TEXTURE_2D);

qglBegin(GL_TRIANGLE_STRIP);



for (i = 0; i < 8; i++)

{

qglVertex3fv(bbox[i]);

}



qglEnd();

qglEnable(GL_TEXTURE_2D);

qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

qglEnable(GL_CULL_FACE);

#endif

What the "#if 0" statement does is make the compiler skip all the code following it until it reaches the "#endif" line, effectively disabling the whole block of code. Well, we don't want it disabled, but then again, we don't want it enabled all the time either. The solution: a cvar (console variable) of course! We'll call our cvar "gl_showbbox", following the pattern of the "gl_showtris" cvar (which oddly enough doesn't work properly; I will get to working on that in another tutorial).

So, let's start by changing the "#if 0" line from a compiler statement to a real "if" statement that checks the value of our new cvar, "gl_showbbox", and is followed by an open bracket (to start the block of code). If you are new to the engine, the statement would read "if (gl_showbbox->value) {", because each cvar holds it's value in the "value" field. Next, change the "#endif" line to a close bracket (to end the block). Your final block should look like this (minus the comments; you may choose to add them):



if (gl_showbbox->value) { // Guy: Show Model Bounding Box

qglDisable(GL_CULL_FACE);

qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

qglDisable(GL_TEXTURE_2D);

qglBegin(GL_TRIANGLE_STRIP);



for (i = 0; i < 8; i++)

{

qglVertex3fv(bbox[i]);

}



qglEnd();

qglEnable(GL_TEXTURE_2D);

qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

qglEnable(GL_CULL_FACE);

} // Guy: Show Model Bounding Box

Now that we have our block of code and cvar check in place, you might think we are ready to compile. NOT YET! We need to define our "gl_showbbox" cvar, so the compiler will know what we are talking about, and then specify its default value, so that Quake II will know how to handle it.

Open the file ref_gl/gl_rmain.c, and search for the definition of "gl_showtris" as a cvar_t:



cvar_t *gl_showtris;

Beneath that line is where we need to place our new cvar's definition, so type exactly the same thing "gl_showtris" has, but for "gl_showbbox", like so:



cvar_t *gl_showbbox;

Now, there is just one more loose end to wrap up before we setup our default value definition. We need to make sure every file in the rendering code can access our cvar, not just the file that defines it. If we didn't, gl_mesh.c wouldn't know what we were talking about! We do this with an external declaration, which to the compiler translates "we are using this variable here, but we aren't defining it here. Don't allocate memory just yet and look for the declaration elsewhere".

To do this, open gl_local.h and scroll down quite a bit until you find the line:



extern cvar_t *gl_showtris;

Just like before, we need to add our "gl_showbbox" cvar underneath that line by copying what's already there. Copy the whole declaration for "gl_showtris" and change "gl_showtris" to "gl_showbbox". Your line should read:



extern cvar_t *gl_showbbox; // Guy: Show Model Bounding Box

Now, we define the default value. Scroll down to the function named "R_Register", and find the line:



gl_showtris = ri.Cvar_Get("gl_showtris", "0", 0);

Again, we need to put our cvar under that one, so copy everything that is written for "gl_showtris", changing "gl_showtris" to "gl_showbbox" in both places. Before I show you what the line should look like, I need to cover one more thing. We want to save the value we set for this on engine shutdown, right? Well, see that zero at the end of the line, the one outside quotes? That specifies the special flags, i.e. special settings to use, for this cvar. Saving on shutdown is a special flag, and we need to set it if we want this cvar saved, so change the zero to "CVAR_ARCHIVE", the flag name for saving the value. Your completed line should read:



gl_showbbox = ri.Cvar_Get("gl_showbbox", "0", CVAR_ARCHIVE); // Guy: Show Model Bounding Box

We're done! Compile, and if you don't receive any errors, you're golden. Just fire up Quake II, load up a map (I used base1 for testing), bring down the console, and type "gl_showbbox 1" at the console. You should immediately see boxes around all entities in view, and even those that aren't (through walls).

This is an excellent tool for mapmakers when trying to decide how high to make an archway/doorway to allow a model/player to fit through.

An explanation of the code:
(this is only for those who want to understand what the newly-enabled code actually does. If you are one of those cut & paste editors, you can stop reading here!) If you're a beginner, you may be wondering what that block of code does that you've enabled. Well, I'll explain it, shortly. The first line of the block, "qglDisable(GL_CULL_FACE)", basically turns off the OpenGL function to hide triangles, those little shapes that make up an OpenGL scene, that cannot be scene from the current camera position. This allows you to see the parts of the model bounding box that are facing away from you. Next, the "qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE)" line enables OpenGL to draw all triangles, both backward and forward facing, as wireframe lines, with nothing in between them (like textures/colors). Then, the "qglDisable(GL_TEXTURE_2D)" line disables texturing, since we don't need them with wireframe anyway. The "qglBegin(GL_TRIANGLE_STRIP)" line tells OpenGL we are about to create a few triangle-shaped strips. The "for" loop goes through each point that makes up the bounding box (8 points make up 6 sides of a box), and sets it to a point on a triangle strip, which creates the visual effect of lines going across from opposite points. The "qglEnd()" line finishes our triangle strips and actually causes them to be rendered. Finally, the last few lines set everything back to normal rendering, as it was before we started drawing the box.



 
Not logged in
Sign up
Login:
Passwd: