Greg Dolley’s Weblog

A Blog about Graphics Programming, Game Programming, Tips and Tricks

Archive for November, 2007

Update: Quake 2 .NET Port with Visual Studio 2008 (v9.0) and Managed C++

Posted by gregd1024 on November 25, 2007

This article is an update to my previous post on 11/18 where I said I’ll post the source code in a couple says. Sorry that it took a little longer than a couple days. 🙂


The last port of Quake II to managed C++ .NET was done by a company called Vertigo Software in 2003. Just like Id Software‘s original release in 2001, Vertigo made their source code available under the GNU General Public License (otherwise known as the “GPL”). Back then, before .NET 2005, managed C++ had a very different syntax. When creating objects there was no way to tell whether that object was a managed type or native type. When dereferencing pointers there was no indication on whether the object was managed or native. Many keywords specific to .NET were prefaced with a double underscore (“__”). An array of managed types could be declared without being initialized. There were many, many other differences in the old syntax compared to what we have today. With the advent of .NET 2005 Microsoft changed pretty much every aspect of managed C++ from the keywords themselves to how destructors and finalizers work (destructors and finalizers basically have reversed rolls in .NET 2005 – not knowing this fact would cause most ports to crash). Microsoft’s reasoning for changing nearly everything was to make it more “logical” and conform more closely with other .NET languages. I’m not sure I agree with the “logical” part (like why I can’t declare a normal array of managed types inside a managed class or managed struct) but it does “feel” more like programming in C# without sacrificing the control of C++. For more details see Microsoft’s conversion guide here.

Microsoft will be removing old syntax support in the next version of Visual Studio (v10.0). Part of the reason I did this port was to keep the managed C++ version alive. Now let’s get into the details!

Download links:

Requirements: DirectX SDK (download here). Must have before compiling! See “Requirements” section for details.

Important note: if you compile the source code in “Release Managed” mode, for some strange reason it won’t run when started from Visual Studio, but will work fine when started from the command line or Windows explorer. However, “Debug Managed” mode works in both cases. The other configurations such as “Release Native” and “Debug Native” also worked.

Even though I pre-compiled just the managed builds in the third download above, if you want to get a zip file containing pre-compiled versions of all the build configurations (managed and native) send me an email via the Contact page of my blog ( I’ll send you a link of where you can download it (note: that download is about 240MB).


The Quake II source is organized into six project files:

  1. game.vcproj
  2. ctf.vcproj
  3. quake2.vcproj
  4. radar.vcproj
  5. ref_gl.vcproj
  6. ref_soft.vcproj

All the projects are contained in the “quake2_VC9_Port.sln” solution located in the source’s root directory. Here is a brief description of each project:

  1. The “game” project contains the nuts and bolts of Quake II. It compiles into a dll (gamex86.dll) which the quake2.exe calls in order to do game logic. If this dll is changed, then how the game plays is also changed. This is how the “capture the flag” version of Quake works – the gamex86.dll is replaced with the dll from ctf.vcproj.
  2. The “ctf” project contains the game logic used in the “capture the flag” version of Quake in multiplayer mode and outputs the corresponding gamex86.dll.
  3. The “quake2” project creates the quake2.exe file. It contains the game logic that is common and doesn’t need to be changed by gamex86.dll. It does stuff like sound management, video blitting (but not actual rendering or OpenGL), file management, etc.
  4. The “radar” project was added by Vertigo Software and is not in the original Quake II game. It is an add-on that allows the player to bring up a HUD (or separate window) showing where objects and enemies are located in the world map relative to the player’s current position. This project produces a dll called “radar.dll”.
  5. The “ref_gl” project contains all the OpenGL code used in the game. It produces the “ref_gl.dll” file.
  6. The “ref_soft” project contains all the software-rendering code used in the game. It is only called when running in software rendering mode or if your video card doesn’t support OpenGL (not likely these days). This project outputs “ref_soft.dll.”


In order for the source to compile you will need the DirectX SDK installed on your computer. Quake II uses DirectX for sound and keyboard/mouse/joystick input. You can download the DirectX SDK here. I personally used the June 2007 release, but it should work with much earlier versions.

After the DirectX SDK installs, check for this environment variable: DXSDK_DIR. It should have been set automatically by the DirectX installation, but if it is not there, set it manually to the root directory in which the SDK was installed (on my computer it was: “C:\Program Files\DirectX SDK (June 2007)\”).

If you have downloaded the source-only zip file, then you will need to copy the following files into the source’s root folder:

  1. Copy any pak files from Quake’s “baseq2” directory (if you just have the Quake II demo, there will only be pak0.pak).
  2. Copy config.cfg from Quake’s “baseq2” directory.
  3. Copy the entire “players” folder from Quake’s baseq2 directory.

Given the default folder names of the zip file, your source tree should now contain the following:

  1. “<drive>:\quake2_VC9_Port\pak0.pak”
  2. “<drive>:\quake2_VC9_Port\config.cfg”
  3. “<drive>:\quake2_VC9_Port\players\*”

These files and directories are needed for the post build events to work (see “Build Changes” for more details).

Game Directory Structure

There are two important directories in the Quake II installation. The first is the root folder and the second is “<root>\baseq2\.” This applies to both the commercial game and the source code tree. However, in the source tree, the root folder is not the source’s root but rather the directory in which “quake2.vcproj” uses as its output. For example, I have the Debug Managed build of “quake2.vcproj” output to “<drive>:\quake2_VC9_Port\Debug Managed\.” It is that path which is the root and thus contains: “<drive>:\quake2_VC9_Port\Debug Managed\baseq2\.”

The root folder contains all the dll’s except for gamex86.dll. Gamex86.dll goes under “<root>\baseq2\.” Other files under baseq2 are the following:

  • Configuration settings – config.cfg
  • Game data file(s) – pak0.pak
  • Saved games (under “.\baseq2\save\”)
  • Network player models (under “.\baseq2\players\”)

Since I obviously cannot distribute the non-demo commercial version of the Quake II “.pak” file(s), if you bought the full version of the game and want to run those levels under this source code, you’d copy all the “.pak” files from the retail game’s baseq2 directory into the source’s baseq2 directory. In fact, it is safe to copy all of the retail baseq2 files and overwrite any in the source tree’s baseq2. There is one caveat though – your saved games will not load under this source because the source’s version string will not match what’s in the save-file(s). But hey, you have the source code now – just find the line which does the version check and remove it! 😉

Build Changes

The following is a list of what build options I had to add, modify, or remove from Vertigo’s source:

  1. Added the following post build events for “quake2.vcproj”:
    • copy “.\config.cfg” “.\$(ConfigurationName)\baseq2\config.cfg”
    • copy “.\pak0.pak” “.\$(ConfigurationName)\baseq2\pak0.pak”
    • xcopy /E /Y /C “.\players\*.*” “.\$(ConfigurationName)\baseq2\players\*.*”
  2. Working directory for “quake2.vcproj” needed to be: “.\$(ConfigurationName)”
  3. Output file for “game.vcproj” needed to be: “..\$(ConfigurationName)\baseq2\gamex86.dll”
  4. The “Additional Include Directories” needed to be “$(DXSDK_DIR)\Include” for these projects:
    • “ref_gl.vcproj”
    • “ref_soft.vcproj”
    • “quake2.vcproj”
  5. The “Wp64” option needed to be removed from all projects.
  6. The “GS” option needed to be removed from “quake2.vcproj.”

The post build events are used to copy the configuration file, data file(s), and player models into the game’s data directory. The configuration file holds settings such as key bindings, video resolution, sound settings, and more. The pak file contains the world map, texture bitmaps, object models (for enemies, items, etc.), and any other data the game needs. All the files inside “.\players\” (which are models and pcx images) are not necessary for Quake II to run in single player mode. In fact, in multiplayer mode I was still able to start a game server and walk around in the world. However, I was unable to customize my player’s skin (an error message would appear at the bottom of the screen saying, “no valid player models found”). When debugging, the working directory for “quake2.vcproj” needs to be the exe’s output directory such that the paths are consistent with what Quake II expects. The output for “game.vcproj” needs to be changed in order for “gamex86.dll” to be copied to the baseq2 directory (see previous sections for details on how this dll works). The Additional Include Directories need to include the DirectX SDK so that the compiler can see the DirectInput and DirectSound header files. The “Wp64” option is removed from all projects in order to get rid of a certain compiler warning complaining that this option is going obsolete in the next version of Visual Studio (v10.0). Removing the “GS” option was only necessary to get rid of a warning in one of the build configurations, but since I like to be consistent I removed it from all the projects.

You may have noticed something about the first group of post build events – if “config.cfg” is moved to “baseq2” then doesn’t this mean my Quake II game settings are reset after every compile? You’re right; you actually only need this file copied the very first time the solution is compiled. After that it only needs to be copied if the one in “baseq2” has been removed.

Compiling the Source

There’s not much to say about compiling the source. Open the solution file (“quake2_VC9_Port.sln”) under the root directory of the zipped attachment. Once Visual Studio has loaded the project, make sure one of the debug build configurations are selected (I use Debug Managed). It compiles like any other Visual Studio project – press “F7” (or whatever key your Build command is bound) to start compiling. The first time around though, I recommend doing a “Rebuild All” just in case.

Hopefully all six projects build successfully with zero errors and zero warnings (if not, please go to my Contact page and send me an email). If you extracted the zip file using its default directory settings, you can go to “<drive>:\quake2_VC9_Port\<build name>\” and run Quake2.exe.

Of course, you could have originally hit “F5” (or whatever key your Debug command is bound) instead of “F7” in order to run the source in debug mode through the IDE.

Known Issues

One issue that I was unable to resolve was with the radar plugin – for some strange reason it always opens a new window for the control no matter whether you’re in fullscreen mode or window mode. In addition, it always starts up behind the main rendering window. While this is not that big of a deal in windowed mode, it is really annoying when playing in fullscreen. It’s possible that there is no problem with the code, but rather Vista is at fault. I don’t know, I never tried testing it in XP. Note: you activate the radar by typing “radar” in the console (the console activates by hitting the “~” key; press again to make it disappear). The radar is only enabled in Debug Managed and Release Managed builds; native mode does not have the radar. Feel free to debug this yourself and, if you fix it, please send me an email (via my Contact page).

Things Not Tested

I haven’t fully tested network play. Starting a server and walking around works fine, but I don’t know whether joining an existing server would work. Also note: this port focused exclusively on the Win32 platform. There were other projects in the Quake II source, such as a Linux version, that I did not touch. I have no idea whether these projects still work.

My Comment Log

If you take a look at the source code you’ll probably notice a lot of lines have comments that begin with this string: “***GREGS_VC9_PORT_MOD***.” A line beginning with this comment indicates that it was changed from Vertigo’s source in order to make the port work. Every one of these lines also contains a description of what was changed and, if applicable, why it was needed. You may be wondering why I did this. Well, the main reason was curiosity – I wanted to know how many lines I’d eventually end up changing. This special comment allows me to easily determine that simply by doing a solution-scope search. The second and equally important reason is simple, it serves as a really good reference for future projects that I port.

A Note About The “Safe” CRT Functions

By default, if you call regular C language CRT functions in a managed C++ project, the compiler will continually spit out warning #4996. This is a really annoying warning that basically suggests you use the corresponding “safe” version of whatever CRT function you’re calling. The safe version typically has the same name as the regular CRT call except it is suffixed with “_s” (i.e. “sprintf” would become “sprintf_s”, fopen would become “fopen_s”, and so on). When you call the safe functions you’re linking against a special version of the CRT which tries to eliminate buffer overruns. Unfortunately, I found out that these functions have bugs! Sometimes there would be runtime errors saying “string not NULL terminated” or “string too short for operation” – neither of which were true. I’d originally planned to port all the CRT functions to their safe counterparts instead of disabling the warning, but after discovering these qwerks and banging my head against the wall not finding a solution, I gave up on that idea. Some of the safe calls were left in (the one’s that worked before I discovered this problem) but only a very small number. Therefore, you will see the “#pragma warning (disable:4996)” preprocessor directive on top of a lot of files.

Performance: Native C++ Versus .NET

On modern computer hardware and the commodity-priced video cards out there, it’s difficult to come up with speed comparisons between .NET versus native C++ when running Quake II. What I mean is this – pretty much all computers with a decent 3D video card run the game at its maximum frame rate anyway regardless of whether native or managed mode is used. However, I did see a difference in performance when I turned on just software rendering and used a high resolution. The speed differences weren’t that much – the .NET version was about 9% slower (94 FPS in native versus 85 FPS in managed).

However, non graphics related things, such as initializing the game and loading maps between levels were noticeably slower in the .NET version. I would wait about seven to ten seconds for the game to load in a managed build versus about two seconds in native mode. The same amount of slowdown was noticeable when switching between levels.

A Screenshot

For those who want to see a screenshot:



All in all, this port turned out to be much more work than I expected. My original thinking was that I’d fix a few dozen or so compile errors and be done in a few hours. Not so! I probably fixed about 2,000 to 2,500 errors (don’t know because the maximum that’s displayed is 100 to 200 before the compiler can’t recover) and had to weed out over 4,000 warnings.

Next I’m going to port Quake III Arena, but not right away; I must rest first….

-Greg Dolley


Posted in Quake 2 C++ .NET Port | 15 Comments »

New 3D Graphics Programming Category

Posted by gregd1024 on November 20, 2007

Since my blog service, WordPress, doesn’t show newly created categories until there is at least one post in them, I’m creating this dummy post as a test.

-Greg Dolley

Posted in 3D Graphics | Leave a Comment »

Quake 2 Port – Visual Studio v9.0 Beta 2 Using Managed Extensions for C++

Posted by gregd1024 on November 18, 2007

I ported Quake 2 source code to C++ .NET using Visual Studio 9.0 Beta 2 with Managed Extensions 2005 (i.e. compiles without the “/clr:oldSyntax” option). It is a derivative from Vertigo Software’s port which used Visual Studio 2003 and the old Managed Extensions framework. The old framework is no longer supported by Microsoft but you can get things to compile via the “/clr:oldSyntax” compiler option. Under the current framework all keywords have changed, destructors and finalizers work differently, and a slew of other things have been modified (for details see: Managed Extensions for C++ Syntax Upgrade Checklist). So I thought it would be cool to take Vertigo’s version and make it current since Microsoft is removing old syntax support (no more “/clr:oldSyntax” option) from the next version of Visual Studio (effectively forcing every company and individual who has code written the old way to do a port). While that may not seem like a big deal (i.e. I thought this project was going to be a piece of cake), trust me, it’s a big pain in the ass. I probably fixed about 2,000 to 2,500 compiler errors (don’t know because the maximum that’s displayed is 100 to 200 before the compiler can’t recover) and had to weed out over 4,000 warnings.

Anyway, I’m still writing the details on this article, so come back in a couple days and I’ll have the code and executable posted.

-Greg Dolley

Posted in Quake 2 C++ .NET Port | Leave a Comment »

Certain Notebook ATI Video Card Drivers Not Supporting OpenGL 2.0 / How to Update Mobility Radeon Drivers

Posted by gregd1024 on November 17, 2007

Let me guess, you got here because you’re trying to find an updated driver for a notebook containing an ATI video card? Are you trying to find a driver that supports OpenGL 2.0? If you were like me — spent a chunk of change on a nice new laptop with an awesome video card, only to find that the driver only supported OpenGL 1.0 (or some version below 1.4) — then you were probably shocked to find that ATI, at the time of this writing, only released Mobility drivers up to the X1800 card. I have the ATI Mobility Radeon 2600 HD running on a Fujitsu N6460 and as you can imagine I was expecting full OpenGL 2.0 support when I bought it (after all, that’s what ATI advertises for this card), but nope, instead I was stuck with only OpenGL 1.0 fully supported and some functions of v1.1 supported. Needless to say, after the discovery of poor OpenGL support, I began searching ATI’s site for an updated driver — there was none. I searched forums, blogs, etc. for an updated driver written by ATI (third party drivers would have been my last resort), but still couldn’t find one. After searching what seemed to be the entire Internet, I found the solution. But first, let me give you a little background on why there are no updated ATI drivers out there.

The whole problem stems from a stupid policy OEM’s have toward ATI (Nvidia is not immune either — see the message on their website after you try selecting a “GeForce Go” model driver for downloading). In a nutshell, OEM’s pressure ATI not to provide support for their device in the Catalyst Mobility driver. This is really stupid. The concern of the OEM’s is that they themselves have their own support system in place and don’t want customers downloading reference drivers from ATI’s website. In my opinion, the type of computer users who know how drivers work and like to install their own are not the type of user that would call the OEM’s technical support line anyway. Terry Makedon, AMD manager for Software Product Management Graphics Product Group gave this statement to Driver Heaven ( in April of 2007:

AMD (formerly ATI) introduced the concept of Catalyst Mobility which is a generic driver that works decently for most laptops. The only way we are able to do this is through permission by a laptop manufacturer (OEM) to include their device in the Catalyst Mobility. We were the first company to provide graphics drivers for laptops to the general public, and we believe there is great value in this. At this point we only have permission from a few vendors and I personally wish more of them would let us. My suggestion is you contact your manufacturer and ask them to have your laptop included in Catalyst Mobility. As for Vista specifically we do not have permissions yet, but as soon as we do we look forward to releasing Vista drivers for laptops.

OK, enough history. So what’s the solution? Easy, you need to download the desktop version of the driver for the card that is in your laptop (so for a Mobility Radeon 2600 HD, you would use the Radeon 2600 HD Series), run a program called Mobility Modder which modifies the desktop driver install files so they work with a notebook, and then simply run the modified setup. This version of the setup runs like any other driver install. When done you’ll have all the desktop driver features running on your laptop! You can get Mobility Modder and detailed installation instructions here:

This program worked like a miracle for me! It saved me from returning my notebook (why would you buy a “gaming” laptop when almost all the games you play use OpenGL and now you can’t play them?). I really like Fujitsu notebooks in all respects, but the fact that they wrote what I believe to be an incomplete video driver and then have the audacity to release it as a “gaming” laptop is just beyond my comprehension. More than half the popular games out there use OpenGL, not Direct 3D! How can it be a gaming laptop if half the games won’t even run properly?! Most will run but will buckle down to using the software-rendered MCD driver for all OpenGL calls not supported by the ICD — an ICD (Installable Client Driver)  is the regular driver written for the video card (DOOM 3 looks very “interesting” running in almost 100% software mode). What were they thinking?! This is my third Fujitsu notebook and the two others I’ve owned supported the latest version of OpenGL that was available at the time of manufacturing. Why didn’t they do the same thing with the N6460 model?!?!?! Ugh!

OK, enough ranting. In case you’re wondering what my notebook specs are, here you go:

  • Intel Core 2 Duo Processor, T7100 @ 1.8GHz
  • 2GB RAM
  • Windows Vista 32-bit
  • ATI Mobility Radeon 2600 HD with 512MB HyperMemory (256MB dedicated, 256MB shared)

And here’s a screenshot of my Catalyst Control Center after updating the driver:


I don’t know why it displays the card as being an X2600 (it should be the regular 2600), but hey, everything works perfectly so I’m not worrying about it.

Anyway, I hope this article has saved you from pulling your hair out and I hope the solution works for you too.

-Greg Dolley

Posted in OpenGL | 11 Comments »