Blog

Quake3 modding quickstart

NOTE: WORK IN PROGRESS!

Install ioquake3

We are going to use the ioquake3 sourceport. And we’re going to compile it ourselfes. You will need the development libraries for SDL2. Consult your package manager how to install them onto your system.

Clone and install ioquake3:

git clone git@github.com:ioquake/ioq3.git
cd ioq3
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug

We make a Debug build so that we can step through the code.


Note

For a release build type Release instead of Debug.


Then, compile and link the programs:

cmake --build build

Done.

You should have a ioquake3 binary in ./build/Debug/. Notice the baseq3 folder. This folder contains all the game-data (textures, models, …) of the Quake 3 Arena game. If you make your stand-alone game some day you will have another folder, such as myCoolGame where all of the gamedata specific to your game go into.

To test our compiled binary out, we can use the Demo-version of Quake 3 Arena, so you don’t have to buy it (althout it doesn’t hurt to do so).
Here ist the data for the Quake 3 Arena demo: Demo.

Notice the fileending of pak0.pk3. This is just a regular zip file in disguise. You can inspect its contents with any ZIP tool on your OS.
Copy the pak0.pk3 into you repos’ ./build/Debug/baseq3 directory.

Now, we also need some more pk3 files, namely, the ones that id-Software published as patches. You can get them from: https://ioquake3.org/extras/patch-data/.
Copy the extracted pk3 files and also place them into your ./build/Debug/baseq3 directory.

Now try to launch ioquake3 from the command line. If everything went well you should now be able to play the demo version of Quake 3 Arena. Take some time and shoot some bots. You deserved it.

Map Editors

Netradiant Custom

Netradiant Custom is a derivative version of id Softwares original mapping tool, called Q3radiant. It runs on all OSes. I had trouble getting the precompiled binary to run on my linux box (it could not load a shared lib). Thankfully, compiling it yourself is not a big deal!
I did find it a bit hard to get used to NetRadiant’s userinterface. GitHub: https://github.com/Garux/netradiant-custom


IMPORTANT

Even if you don’t want to use Netradiant Custom and decide to use TrenchBroom (see below) instead, you still need some tools that come with Netradiant Custom but not with TrenchBroom. Thus, downloading it is required.
For the following steps the program q3map2 is needed. Make sure it is in your system-path so it is callable from anywhere within your terminal!


TrenchBroom

Trenchbroom is a joy to use as its UI is so clean and most of the functions can be figured out by just guessing. However, there is a very good documentation available: https://trenchbroom.github.io/manual/latest/
You can download it from: https://trenchbroom.github.io/.
You will need to tell TrenchBroom where your gamedata lives. For now, point it to the repo’s directory that has the baseq3 directory in it, that is the Game Path:
trenchbroom setup
TrenchBroom reads all assets from the pk3 files inside baseq3. For now, ignore the other two paths you can set (q3map2 and bspc).

If you navigate to the Face tab inside TrenchBroom you should now see all the available textures inside the pk3 files that lie in baseq3.


IMPORTANT

If you are using TrenchBroom on Wayland then start it with:

QT_QPA_PLATFORM=xcb ./trenchbroom

Compiling the Map

Create a new folder called pak10.pk3dir inside baseq3. Inside pak10.pk3dir create a folder named maps. Save your map from TrenchBroom or Netradiant Custom inside baseq3/pak10.pk3dir/maps/ and make it your cwd in your terminal. Type:

q3map2 -bsp <yourmapname>.map
q3map2 -vis <yourmapname>.bsp
q3map2 -light <yourmapname>.bsp

The first command compiles your map into BSP-tree. BSP stands for Binary Space Partition. It is a nifty datastructure that works really well for collision detection and hidden-surface-removal determination of static geometry.
The second command calculates the PSV, which stands for Potentially Visible Set. This is another optimization pass that lets the engine discard all triangles that cannot be seen from the current viewers camera position inside the gameworld. Thus, those triangles never get passed to the renderer. Quite frankly, if you just render Quake 3 Maps with relatively new hardware (maybe 2014+) it probably is faster to just render all of the world’s triangles every frame. GPUs have just become so fast in rasterizing triangles that the cost of figuring out if you can discard 50k triangles is higher than just feeding them into your GPU and let it render them. However, I do believe that the PSV is also used for spatial Audio playback. But I am not sure yet, I will have to dig into the code more to be sure.
The third command, finally, creates the lightmap. A lightmap essentially is a texture that contains diffuse precomputed illumination. It will get blended with the texture you have assigned to geometry inside your Map-Editor.

Starting your Map

In order to start your map inside ioquake3 you go into your build/debug/ folder and type:

./ioquake3 +devmap <yourmapname> +set sv_pure 0

+devmap tells the engine you load your map in debug-mode. That means you can issue console commands inside the engine (more on that later) to make yourself invincible, fly around, etc.
+set sv_pure 0 sets the in-engine variable sv_pure to 0 (=false). That means that the engine loads maps, texture, models, etc. from within folders. They don’t have to be inside a pk3 archive. It would be pretty annoying if you had to first pack everything before testing it, wouldn’t it?


NOTE

In order for the engine to use a folder as an assets-resource that folder must have the extension .pk3dir! +set sv_pure 0 is not enough!


Debugging the code with Visual Studio Code

It is straightforward to setup VSCode for debugging ioQuake3. Install the CMake Tools from Microsoft: cmake tools from microsoft in vscode


NOTE

If you have created a build directory already like in the beginning of the article, I recommend to delete the CMakeCache.txt inside it as it might confuse VSCode when configuring the project.