Greg Dolley’s Weblog

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

Update: Quake 3 Arena .NET Port is Done!

Posted by gregd1024 on January 22, 2008

Yup – I’m now done porting Quake III Arena to managed C++ with Visual Studio 2008/v9.0 and .NET v3.5. My apologies to the guys on my private email list for getting this post out a week late. I ran into massive problems getting the Release build to work, even though there was no difference between its configuration and the Debug build (the latter of which has been working perfectly for two weeks now). Turned out to be one of those, “…damn it! How could I have been so stupid?!” problems/solutions. The Release build doesn’t look in the same directory for DLL’s as the Debug build.

Before I begin explaining the port, I’d like to clarify one thing. Someone emailed me last week regarding this port and judging from his/her message it led me to believe that some people don’t understand the difference between a .NET port versus simply compiling a C++ application with MSVC++ 2008. Here’s the difference: taking the Quake III codebase and making the changes necessary so that it will compile with Visual Studio 2008 is not a .NET MC++ port. That is a C port to a different compiler. Yes, C not C++; the project files included in Id Software’s codebase are all set to compile as native C. Furthermore, changing the settings to compile everything as C++, then fixing 3,000 compile errors, is also not, I repeat not, a .NET port. That is a native C++ port of Quake III to a different compiler. Lastly, taking the former C++ build I just mentioned, turning on the “/clr” Visual Studio option, fixing 28,000 compile errors with 4,000 warnings, patching all managed to native calls such that the first run doesn’t “blue-screen” your machine, and finally doing everything else necessary to be able to view the EXE with its supporting DLL’s under ILDASM (the .NET CLR disassembler), now THAT is a .NET port! πŸ˜‰

Anyway, 99% percent of this port gets compiled into IL / CLR bytecode. The exception is a few small functions which contain inline x86 assembly. Obviously I can’t do anything about those. Now let’s get into the details…

Before Getting Started

As I explain in the post which started this effort three weeks ago, the QVM generation code was not ported (see the previous post for why). Therefore, mixing game DLL’s with QVM’s or running your own QVM’s will not work. The known issues in this port stem from old QVM code. So make sure you’re using all DLL’s in order to run this port.

Get the Source Code

First thing’s first: you’ll need the retail copy of Quake III to run this source, it will not work with the demo version. I know what you’re thinking – “if I have the source, I can circumvent the license check, right?” Wrong. The license check isn’t the problem. The problem is that there are a few big differences between the structure of a demo PK3 data file and a retail PK3 data file. You’d have to change the code to read the demo format, which nobody has unless you work for Id Software.

Here is the download link:

Requirements

In order for the source to compile you’ll need the DirectX SDK. Quake III uses it for sound and keyboard / joystick / mouse input. You can download it here. I used the June 2007 release, but it should work with earlier or later 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)\”).

Projects

The Quake III source is organized into eight project files:

  1. botlib.vcproj
  2. cgame.vcproj
  3. game.vcproj
  4. q3_ui.vcproj
  5. quake3.vcproj
  6. renderer.vcproj
  7. Splines.vcproj
  8. ui.vcproj (originally part of the Id Software source, but I removed it from the solution)

The master solution file containing all these projects is under “<source root>\code\.” It is the only solution file in that directory. Open it with Visual Studio 2008 to get started. Hopefully there are no errors on loading; if there are, please contact me.

Note: the “ui” project was originally part of Id Software’s source tree, but I removed it from the solution because it’s not needed (the project is still contained in the download, just not referenced). This project is used for the Quake III Team Arena (TA) game which is not part of this port.

Game Directory Structure

There are two important directories in the retail Quake III installation: the root and “baseq3” located directly underneath the root. The root folder contains “quake3.exe” and “baseq3” contains the three supporting DLL’s needed to run the game. You won’t find these DLL’s in the commercial install of Quake III, but after compiling the source they will be put there (if you’re curious as to why this is, check out my earlier post about installing a Quake III mod).

I would recommend installing another Quake III instance under the path “c:\quake3” if you don’t already have it there. That way, you won’t have to edit any of the project settings. And, more importantly, you won’t overwrite your commercial copy of Quake III after compiling the source. There’s nothing wrong with having two instances of the game installed on the same machine – you can have one as the original, and the other as a test-bed when messing with the source code.

Steps to Run the Source

First, if you don’t have the commercial version of Quake III installed under “c:\quake3\” then you’ll have to change the project settings a bit. The outputs of the following three projects will have to change:

  1. cgame.vcproj
  2. game.vcproj
  3. q3_ui.vcproj

Locate the “Output File” setting for each project under Visual Studio’s Project Properties dialog (this would be under, Project -> Properties -> Configuration Properties -> Linker -> General -> Output File). Change each of them to the following:

  1. For cgame: c:\<quake3 install dir>\baseq3\cgamex86.dll
  2. For game: c:\<quake3 install dir>\baseq3\qagamex86.dll
  3. For q3_ui: c:\<quake3 install dir>\baseq3\uix86.dll

Change “<quake3 install dir>” with whatever directory you have the Quake III game installed.

Now set the build configuration to Debug. Yes, you could do Release, but if anything goes wrong the Debug build will give you better diagnostic information. You may also notice other build configs in the drop-down list, such as “Debug Alpha,” “Debug TA,” and a few others – don’t touch these!! The only two you should be interested in are “Debug” and “Release.” The others are for Team Arena and non-Intel builds. They won’t work for this port.

Now select “Build -> Rebuild Solution” from Visual Studio’s menu options. If everything builds with zero errors and zero warnings, great! If not, please contact me.

Set quake3.vcproj as the startup project. It should already be set by default, but I’ve noticed Visual Studio 2008 seems to have a bug with this – sometimes, for no reason, the startup project will get changed.

Run the solution directly from Visual Studio. Now start fragging! πŸ˜‰

Note: you could run the game directly from a command line, but you’ll need to start it like this:

“quake3.exe +set sv_pure 0 +set vm_game 0 +set vm_cgame 0 +set vm_ui 0”

Known Issues

Sometimes on fast machines in single player mode, if you add a lot of additional bots after joining an arena, the game will have connection problems. The phone jack icon will display in the corner and you won’t be able to move your player. This bug also happens in the commercial version so it’s not a new bug.

However, here’s a bug caused by the port which only happens in Release builds (Debug works fine). When connecting to some third-party servers on the internet, usually one supporting DLL fails to load (usually uix86.dll). When this happens, Quake III’s default behavior is to load the QVM files contained in the PK3 data files. As explained earlier, mixing QVM’s and DLL’s don’t work, so you’ll get very weird behavior if this scenario arises.

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 the original codebase. It also contains a brief explanation on what was changed. This comment was added to almost every modified line except when getting rid of a keyword conflict caused by member variables being named “generic” (since “generic” is also a .NET keyword). This member was used on nearly 2,500 lines and I didn’t see the point in wasting time repeating the same comment over and over. Instead, one comment was added to the top of every module affected by this conflict along with what was done to resolve it.

A Screenshot

Here’s a screenshot at the startup menu with the console pulled down. Notice how it displays which .NET runtime is executing the game:

image

Conclusion

If you have any questions or problems with this port, please send me an email via my Contact page.

Thanks for reading! πŸ˜‰

-Greg Dolley

*Get new posts automatically! Subscribe via RSS here. Want email updates instead? Click here.

101 Responses to “Update: Quake 3 Arena .NET Port is Done!”

  1. Vitaly said

    Awesome, Greg! Will you be porting it to C#? πŸ™‚ I’ve tried compiling the solution and have bunch of this kind of errors, what I’m doing wrong?
    Error 1 fatal error C1083: Cannot open include file: ‘assert.h’: No such file or directory e:\temp\quake3_arena_vc9_net_mcpp_port\code\game\q_shared.h 85 botlib

  2. gregd1024 said

    Hi Vitaly,

    C# port? I have thought about it. πŸ˜‰ It would take a really long time; so I haven’t decided yet.

    About the errors – that’s really weird since assert.h is a standard system header. Is that the very _first_ error you get? If not, what is? Sounds to me like that error is a side-effect of something bigger.

    Are you using the Express version of VS 2008 or Professional?

    If you comment out the include, then do you get other headers not found, or is it OK after that?

    -Greg

  3. Sidu said

    This is awesome! Dude, you’re the man.

    C#? What’s the point unless you’re re-architecting the q3a codebase to use C# language features? This is way cool as is.

  4. […] Greg Dolley has posted in his blog about his port of Quake 3 Arena to managed C++. Although he did “only” port it to managed C++ (and not C#) is it freaking awesome and a lot of work: […]

  5. Vitaly said

    Hi Greg,

    It turned out that I did not have C++ in VS installed :-D. Its weird that VS loaded C++ projects without any warning and even tried compiling them…

    Thanks.
    Vitaly

  6. gregd1024 said

    Hehe, thanks Sidu! πŸ˜‰

    Why C#? Yeah, I know it’s pointless considering with this port you can now use all the .NET classes and do everything that C# can do (albeit with a different syntax). But I don’t know why, I just think it’d be kind of cool to see a C# version running side by side with a MC++ version.

    -Greg

  7. gregd1024 said

    Vitaly,

    Whoa, you didn’t have C++ installed and it still loaded the project?! Freaky! Well, that sure explains the errors then. LOL! πŸ˜‰

    Thanks for the update.

    -Greg

  8. kirill said

    What are the performance penalties of managed execution? Can you give us some numbers?

  9. […] Quake Arena ported to .NET ο»ΏManaged C++ apparently. […]

  10. […] Greg Dolley has done something amazing.  Greg ported id software’s video game, Quake 3, to .Net. […]

  11. Miguel Sousa Filipe said

    The name is not Managed C++, but C++/CLI

  12. […] Greg Dolley has done something amazing.  Greg ported id software's video game, Quake 3, to .Net. […]

  13. gregd1024 said

    Kirill — I did the port on a high powered gaming PC making it hard to get meaningful numbers. Both versions run at the max vsync rate (my monitor is 60Hz, so I get 60 fps). I will try them on a couple slower machines within the next few days to get some relevant performance stats. Stay tuned.

    -Greg Dolley

  14. “and do everything that C# can do”

    Well, not really. As of the 2008 release, C# can do expression trees and lambdas, but C++/CLI cannot, to my knowledge.

    However, for the purposes of this project, it’s *probably* a very minor thing unless there are sections of code that do some interesting queries of collections.

  15. […] Greg Dolley has done something amazing.  Greg ported id software’s video game, Quake 3, to .Net. […]

  16. Baczek said

    I don’t know which version you used, but I hope it wasn’t id’s original source. icculus.org hosts a version with a metric boatload of bugfixes (and some new features), not having them included would be… bad.

  17. Bil Simser said

    The point of moving to C#? Get it to C# then swap out the DX calls with XNA ones and publish it to the XBox 360, that’s why. Should be a matter of getting the compiled assemblies, opening them up in Reflector, dumping the code out in C# and fixing any weirdness (which will be a LOT easier than the 28,000 errors you had before). Trust me, I’m doing the same thing with the original Sim City code as it moves to XNA. Great job on the port! Looks fab.

  18. Adam said

    Theoretically, if you ported it to C#, couldn’t you then port it to asp.net?

  19. Sebastian said

    Why don’t you just turn off the vsync? You can do this in your video drivers. I believe Quake 3 has a com_maxfps as well that you need to disable (set it to 0 I think? Or something high). Then just do the standard timedemo.

  20. Ricardo Santos said

    My stomach had an explosion with happiness!!
    you rock! (C# would be cool, but..this is soooooooo neat)

  21. seerox said

    Umm…no.

  22. gregd1024 said

    Kirill,

    Using Sebastian’s suggestion I ran timedemo’s without vsync and turned off the fps cap. Here are the numbers (this is from demo “four” that comes with the Ultimate Quake box you see in stores). I ran each instance three times to make sure there weren’t any flukes:

    Running original Quake III commercial game:

    Test run #1: 324.2 fps
    Test run #2: 330.9 fps
    Test run #3: 332.5 fps

    .NET port:

    Test run #1: 328.6 fps
    Test run #2: 336.9 fps
    Test run #3: 336.8 fps

    At first it may seem weird that the .NET version is slightly faster, but remember, the original commercial quake3.exe uses its own custom interpreter to run QVM files responsible for all of the game logic (except rendering of course). My .NET port uses DLL’s also _interpreted_ by the .NET framework instead of QVM’s. So what you’re really doing is comparing who’s interpreter is faster.

    -Greg Dolley

  23. gregd1024 said

    Miguel – When did the name change?

    -Greg Dolley

  24. gregd1024 said

    Keith,

    Thanks for the info. I didn’t know that. Do you know if VC++ will support those features in the future?

    -Greg Dolley

  25. gregd1024 said

    Baczek,

    I used the v1.32 source that is in the technology downloads section of Id Software’s site. I don’t think this is the “bad” version you’re talking about. It’s the same version released to stores under the Ultimate Quake Collection. The CHANGELOG lists numerous bug fixes and was last updated on 5/22/2004.

    -Greg Dolley

    • Pablo Rosatti said

      I think Baczek is right, ioquake is the same q3a engine you used but with fixed a lot of bugs, and added a lot of extras to made it more compatible.

      Thanx for your excellent work.

  26. gregd1024 said

    Bil – very good point indeed!

  27. gregd1024 said

    Adam – no, ASP.NET is used for web development.

  28. Timor said

    What is the purpose of such a port ?
    why not keeping it native ?
    Rewriting with C++/CLI, why not, and make it a safe & pure clr app (hard work)

    Do you want to add plugin in c# ?

  29. the dude said

    LOVE IT!
    LOVE IT!
    LOVE IT!

    Compiling right now…
    I wonder how difficult it would be to stick an XNA overlay HUD on top of the scene? In any case, I’ll have a fun weekend tinkering around with the bot AI while its 14 degrees outside.

    Do you think you could do a post in detail of how you translated some of the native calls to framework calls? Did you use some sort of string operation to batch process all the files, or what? Curious…

  30. gregd1024 said

    Timor,

    The purpose – well, it started out as something just for fun. I like to do things that are hard in programming. I’m the kind of programmer where if my ballpoint pen had a 2Hz CPU with 4 transistors and 8 bytes of RAM, I’d try to write an OS for it. LOL!

    After my initial porting efforts started to work where I had a C++ version without CLI, I began messing around with some of the in-game weapons. I made a few simple mods with the rocket launcher and shotgun – it became really fun and at that point I realized most mods don’t need to be C or C++, a managed language would be more than adequate to code these parts of the game without having to worry about performance. Furthermore, development time typically shrinks as a result of using a .NET language over C or C++. This means new features can be coded quicker and with less of the idiosyncrasies common to native C.

    After pondering things for a while, I decided to go all out and convert the entire codebase to C++/CLI.

    So to answer your question, yes, I have things I want to write in C# but more importantly there are things I want to try in _some_ .NET language, it doesn’t necessarily have to be C#.

    Why not go pure clr? I contemplated that question for a long time actually. At first I looked at it from the perspective of writing a game from scratch; I asked this question – if you had started writing a game from line zero and it had to be .NET, would you use pure or mixed-managed? My first answer was: go with pure. But then I thought some more – given that FPS games are highly performance driven and you must squeeze every last ounce of power from the CPU – going with pure would be a bad decision. You want the performance gains from doing mixed-managed. In the end, everything will still turn into 100% CLI bytecode anyway.

    -Greg Dolley

  31. Timor said

    Thanks for your answer, I understand better your approach.

    I think too that to add some additional code (weapon as you said for example), it’s easier to do it with another .net language. In this way, I understand why you try to port the code. (and for your pleasure too πŸ™‚ ).

    About pure clr question, I think that mixed-mode in bad for performance, going from managed world to native world cost a lot. Transition, chunking, double chunking are very time critical. But I’m not abble to know if pure app will be faster than mixed-mode app. It depends on the architecture. The less transition there are, the faster it will be

  32. Miguel Sousa Filipe said

    Then name changed from Managed C++ Extensions (which everybody abreviated to Managed C++) to C++/CLI, right about when VS2005 came out, I think.
    A good intro:
    http://www.codeproject.com/KB/mcpp/cppcliintro01.aspx

    the standard is here: http://download.microsoft.com/download/9/9/c/99c65bcd-ac66-482e-8dc1-0e14cd1670cd/C++-CLI%20Standard.pdf#search=%22C%2B%2B%2FCLI%22

    and the design rational for C++/CLI is here:
    http://www.gotw.ca/publications/C++CLIRationale.pdf#search=%22C%2B%2B%2FCLI%22

  33. Kevin said

    Interesting. As someone said it would be interesting to port to C#. Then I was thinking the next step would be to port it to XNA. I see The Dude has the same ide πŸ™‚

  34. […] Quake 3 ported to .Net Posted by: DG at: 4:40 pmLast updated: January 25, 2008 at 4:40 pmFiled under: .NET, Gaming  1 Views Greg Dolley has done something amazing. Greg ported id software’s video game, Quake 3, to .Net. […]

  35. gregd1024 said

    The Dude,

    Awesome! Glad you’re really liking it!! πŸ™‚ As far as adding XNA, take a look at win_qgl.c in the “renderer” project. You’d have to change those functions to their XNA equivalent. I know things are done much differently in OpenGL versus XNA, buy hey, no one said it was going to be easy. πŸ˜‰ Or you can try and figure out how to make an OpenGL rendering context work in tandem with the XNA’s GraphicsDevice object. Then you wouldn’t need to convert everything, just the functions you needed. Here’s something you can try: have OpenGL render to the back buffer like normal but instead of flipping it to the screen, read the raw buffer data with glReadBuffer() and glReadPixels(), then use that data to fill in XNA’s screen buffer (or back buffer). Now your code is free to draw whatever it wants with XNA knowing that the output from OpenGL’s rendering is already there. Something like that would be really cool if you could get it working.

    As far as native to framework calls – yeah, I’ll write a post about how to do the marshalling in general. How I physically did the code changes – manually. In fact, very few calls actually ended up needing a conversion. You see, the time consuming, tedious part is not the modifications for marshalling, but actually _checking_ all the functions to see _whether_ marshalling is needed in the first place. You can’t rely on simply running the project, and if it works, assume that all the calls are OK – it could coincidentally work nine times in a row and crash on the tenth.

    All code modifications were manual except for changing variables which happened to be keywords in .NET that aren’t keywords in native (such as the word “generic”) – there was no way I was going to type all that manually (there were sooooooo many uses of the word “generic” and “new”). I used VS’s search/replace to quickly check where the violations were and change them if necessary.

    -Greg Dolley

  36. gregd1024 said

    Timor – Sorry, I should have been clearer in my comment; by mixed-mode I simply meant using the “/clr” option without “pure.” I didn’t mean having native x86 code mixed into the .NET binaries – in that case, I agree with you, there would be performance penalties. I just meant keeping things like “structs” as-in instead of converting them to “ref class” objects. Regular “structs” are converted to value types anyway if you look at the disassembled IL code – they are _not_ kept native. I believe these are faster than ref classes.

    Miguel – Thanks for the name-change info. I learned something new! πŸ™‚

    Kevin – I think it’d be cool to see a C# version using XNA. Does XNA support C++/CLI? Sorry if this is a stupid question, I thought it did, but doesn’t seem to after reading some stuff on google.

    -Greg Dolley

  37. […] Now that’s pretty cool…  A .NET port of the Quake 3 Arena source code. […]

  38. Tyler said

    I realize what I’m about to say is blasphemy but I’ll say it anyways…………

    An interesting challenge would be to take the C++ code and convert it to VB.NET. VB is constantly referred to as a “toy” language when I think the fact of the matter is it really depends on the programmer and the skill level involved. Brilliance can be expressed in any language; programming languages are just tools after all.

    The reason I suggest this is two fold:

    1) It would be very interesting to see performance differences going from C++ to VB.NET with such an involved and complex program. Today’s hardware is so powerful; it would be very interesting indeed.

    2) There aren’t many sophisticated or cool examples written in VB.NET. At least not of the magnitude I’m proposing above. You’re more likely to find “experimental” stuff in VB6 (blah). VB.NET and VB6 are night and day, and the former is on par with C#. This would be an interesting exercise for all parties, particularly VB.NET developers who don’t always get the learning experiences they should.

    Thanks,
    Tyler

  39. gregd1024 said

    Tyler – I hate to say it, but I actually agree. Basically, if I were to do a C# port (something I’m considering but haven’t come to a hard decision yet) then it would not be too difficult at that point to port it once more to VB.NET (compared to going straight from C++/CLI to VB.NET). Seeing how things performed under VB.NET would indeed be interesting.

  40. Enrico said

    Hello,

    Great Job, it is very useful but, anyway, Ive a problem:

    I compiled all in the right directories but the console says that default.cfg file can’t be loaded.

    Here the log:
    _______________________________________
    Q3 1.32b win-x86-debug Jan 27 2008
    —– FS_Startup —–
    Current search path:
    C:\quake3/baseq3

    ———————-
    0 files in pk3 files

    Running in restricted demo mode.

    —– FS_Startup —–
    Current search path:
    C:\quake3/demota

    ———————-
    0 files in pk3 files
    —– CL_Shutdown —–
    ———————–
    Couldn’t load default.cfg
    _______________________________________

  41. gregd1024 said

    Enrico,

    You’re running the shareware demo version of the game. It will not work with the demo (see “Get the Source Code” section of the post for an explanation).

    -Greg Dolley

  42. […] Quake 3 .NET Portierung! […]

  43. […] Quake 3 ported to .NET 3.5 […]

  44. […] Sul blog di Greg c’è il post che analizza in dettaglio tutte le varie fasi del porting (LINK) […]

  45. […]  Dan Pick of the week: Greg Dolley's port of Quake 3 from C to C++/CLI […]

  46. tam said

    You just made my day. :))

    more seriously, I really like to read this kind of news in the morning and I am looking forward to see a port to C#.

    Regards,

    Tam

  47. Enrico said

    Hello,

    I know I’m running the TA Version but I don’t know how to run the normal version

    And also, now I have the retail version of Q3 but It still wont the default.cfg file.

    Please help me!

  48. gregd1024 said

    Hi Enrico,

    First, make sure the build configuration in Visual Studio is set to “Debug” or “Release” – there are other’s like “Debug TA” (Team Arena Debug) which you don’t want.

    If you haven’t done so already, try installing Quake 3 under “c:\quake3” – the same directory I used for debugging.

    If trying those two things don’t work, then paste your Q3 log again so I can take a look.

    -Greg Dolley

  49. […] Update: Quake 3 Arena .NET Port is Done! […]

  50. James said

    Does anyone have a copy of the built files, I do not have visual studio to create it.

  51. Norb said

    Everything is working fine.

    But when I join a localhost game, single or multiplayer, the map textures are missing. i only see the crosshair + items and effects repeating over and over as I move around.

    what did I do wrong πŸ™‚ ?

  52. gregd1024 said

    Norb,

    This happens when the DLL’s can’t load. Pull down the console (with the “~” key) and you’ll see that the QVM’s were loaded instead. Check the baseq3 directory in the Q3 installation folder and see that all three DLL’s are there – qagamex86.dll, cgamex86.dll, and uix86.dll. On my computer this is “c:\quake3\baseq3.” The project settings are made to output the DLL’s there, or the root (c:\quake3) if it’s a debug build. Try setting your Q3 installation to this directory and do a full rebuild. Let me know if this fixes it.

    -Greg Dolley

  53. Norb said

    my first problem was the _getcwd function used in win_main.c. it always returns my development (source c:\dev\cpp\quake3\code) directory instead of the directory from where quake3.exe is started (c:\quake3).

    i rewrote the functions using _getcwd (dirty) to return c:\\quake3 as cwd.

    in the quake3 console log i can see that it loads the dll files until i actually start a game. (then it loads the qvm, and stuff gets weird ;))

    anyway if i start quake3 with the commandline:
    quake3.exe +set sv_pure 0 +set vm_game 0 +set vm_cgame 0 +set vm_ui 0
    the port works fine, also creating and joining games.
    if i just start quake3.exe i get the same behaviour as while debugging from visual studio.

    so i think my other problem has todo with how visual studio starts the quake3.exe when i start the debugging.

  54. gregd1024 said

    Norb,

    Yeah, if those command line options aren’t used, Q3 will load one DLL at startup and then use the QVM’s after launching a game. I should have taken out QVM support completely when doing the port, but oh well, too late now.

    As far as _getcwd – it will return your source directory while in the debugger unless you override it in the project config. In my settings (and in the public release) I just forced c:\quake3 as cwd. But sometimes, I’m not sure why, Visual Studio seems to overwrite this setting with the default, breaking the installation. You can set it back through “Project->Properties->Configuration Properties->Debugging->Working Directory.” Also on this same page, there’s a setting called “Command Arguments” – you need to set that to the arguments you used before:

    “+set sv_pure 0 +set vm_game 0 +set vm_cgame 0 +set vm_ui 0”

    So try it with those two changes and let me know how it goes.

    -Greg Dolley

  55. Norb said

    Greg,

    those settings make sense of course πŸ™‚ i just didn’t think of setting them.

    with manually setting the working directory and command line for the quake3 project, everything now works smooth and as it should πŸ™‚

    Thanks alot!

  56. James said

    This is a great project. It had occurred to me that I should attempt this a year or so ago, but I quickly decided it was far beyond my level of ability.

    Do you have any plans for the project in the future? Perhaps you could develop a simple extension manager that allows modules written in pure CLR languages to be loaded that contain game logic and other such functionality. This way uses could interact with the engine in C# and VB.NET amongst others.

    Once again, excellent work!

    Regards,

    James

  57. gregd1024 said

    James,

    Thanks for the kind words! πŸ˜‰

    Yes, there are plans for the future. In fact, an extension mechanism like the one you described is already in the works. Although it’s just in the beginning stages right now – I’m laying out the architecture and deciding how the extensions will work from a modder’s point of view (figuring out what is the most useful design).

    If you have any suggestions on how you’d like to see the extensions work, let me know.

    -Greg Dolley

  58. James said

    Greg,

    I imagine that the task of designing the extension architecture is much more complex and time consuming than the task of actually implementing the code.

    I’m no expert on the matter but I have a couple of suggestions: I think that the extensions should be able to ‘hook’ functionality from the game engine. When the extension applies this hook, all the data that would have passed through the original engine function is passed through a local function within the extension code. The developer then has the option of either modifying the data (which would be passed as function arguments) and then allowing the original function in the game engine to execute (this would allow for slight modification) OR they can choose not to execute the original code and implement their own code entirely. This could completely alter the behaviour of the original function.

    For instance, developers could hook the behaviour routine for a certain weapon, and make slight modifications, or they could entirely replace the original behaviour.

    It may also be wise to add support for the game’s event messages and similar features.

    Apologies if none of this made sense!

    Regards,

    James

  59. gregd1024 said

    James,

    Actually, you made perfect sense! πŸ˜‰ Thanks for the input.

    -Greg Dolley

  60. Jobs said

    Greg, how about supporting /clr:pure? Advantages of /clr:pure Better Performance: Because pure assemblies contain only MSIL, there are no native functions, and therefore no managed/unmanaged transitions are necessary. (Function calls made through P/Invoke are an exception to this rule.)

  61. gregd1024 said

    Jobs,

    Changing the code to support /clr:pure would be about the same amount of work as doing an entire C# port. I’d rather use that time to actually do a C# port.

    -Greg Dolley

  62. Chris said

    Hello,

    Thanks for the great port. I am having a problem however, I want to use custom ui scripts as well as create a small team based game but if you try to compile with the Debug TA or Release TA, you get various errors and warnings.

    However, If you just compile the plain stock code, it’s fine. Will the Team Arena / Mission Pack code changes be made?

    If I’ve missed something or someone has gotten it to compile with the missionpack support, please email me. cbunting99@gmail.com

  63. gregd1024 said

    Hi Chris,

    TA wasn’t ported, just regular Quake 3 Arena. I don’t have any plans right now to change that part of the code. Actually, the TA portion is rather small and should be pretty easy for you, or anyone else, to convert. Turning on the Debug TA or Release TA configuration simply adds about five percent more code through #ifdef’s.

    If you want to try and get TA working yourself, I can certainly help you if you get stuck. I don’t think any algorithms would need to change, and I also don’t think TA adds any new data structures (but it does modify some existing one’s). So it should be pretty straight forward.

    -Greg Dolley

  64. Chris said

    Hello Greg,

    Thanks for the reply. I actually came across a site that has some code for using the ta style menu without having to use the ta/mission pack stuff.

    Just curious. Do you do anything with OpenGL and GLSL shaders? I’ve found on implementation in another q3 engine but I am unsure if that hard coded (Evolution Q3) version is the best way. If you search for q2e or Quake 2 Evolved at sourceforge, you can find in svn the Q2 Overdose source which contains doom 3 style shaders.

    I am interested in getting glsl shaders working in this code but while there are a ton of pre-written shaders, there seems to be no updated code examples for loading the shaders. If you have any ideas or if anyone has any links, I’d like to see them if you’ll email me at the addy above.

    Thanks,
    Chris

  65. gregd1024 said

    Chris,

    No, there are no GLSL shaders in the Q3 code.

    Loading Doom 3 style shaders shouldn’t be any different from regular OpenGL shaders. I’ve always used these extension functions in my programs:

    -glCreateShader
    -glShaderSource
    -glCompileShader
    -glCreateProgram
    -glAttachShader
    -glLinkProgram
    -glUseProgram

    Loading my shaders looks something like this in pseudo-code:

    LoadShaders()
    {
    my_shader = glCreateShader(GL_VERTEX_SHADER or GL_FRAGMENT_SHADER);
    glShaderSource(my_shader, 1, my_shader_source_string, NULL);
    glCompileShader(my_shader);
    my_program = glCreateProgram();
    glAttachShader(my_program, my_shader);
    glLinkProgram(my_program);
    glUseProgram(my_program);
    }

    -Greg Dolley

  66. Chris said

    Hello Greg,

    Was going through the code and checking out Nvidia’s NVSG and thier OpenGL SDK 10. I starting working on some implementions when I noticed some code that didn’t seem to be actual C++ code. I was thinking that this was a complete C++ rewrite of the quake3 code? Is this just a conversion to compile with .Net?

    Example: cgame/cg_main.c (Your change)


    void CG_RegisterCvars( void ) {
    int i;
    cvarTable_t *cv;
    char var[MAX_TOKEN_CHARS];

    for ( i = 0, cv = cvarTable ; i vmCvar, cv->cvarName,
    cv->defaultString, cv->cvarFlags );
    }

    // see if we are also running the server on this machine
    trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) );
    cgs.localServer = (qboolean)atoi( var ); // ***GREGS_VC9_PORT_MOD*** -- added typecast(s)

    forceModelModificationCount = cg_forceModel.modificationCount;

    trap_Cvar_Register(NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
    trap_Cvar_Register(NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
    trap_Cvar_Register(NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
    trap_Cvar_Register(NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE );
    }

    I see the one line above with your comment. But the rest of the code is unchanged?

    Now, here is another cgame/cg_main.c (Q3++)


    void CG_RegisterCvars( void) {
    int i;
    cvarTable_t *cv;
    char var[MAX_TOKEN_CHARS];

    for ( i = 0, cv = cvarTable ; i vmCvar, cv->cvarName,
    cv->defaultString, cv->cvarFlags );
    }

    // see if we are also running the server on this machine
    Cvar::VariableStringBuffer( "sv_running", var, sizeof( var));
    cgs.localServer = atoi( var)?true:false;

    forceModelModificationCount = cg_forceModel.modificationCount;

    Cvar::Register( NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
    Cvar::Register( NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
    Cvar::Register( NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE );
    Cvar::Register( NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE );
    }

    This has me a bit confused. The latter code is from a partial conversion of the Q3 code. I may be misunderstanding the differences with managed c++ .net code. It just doesn't look like any of the c++ code that I've found.

    Chris

  67. John said

    Hi there,

    First off… fantastic job you’ve done here.

    I’m a real novice when it comes to c++, but following your tutorial, from downloading VS 2008 c++ express edition to configuring the environment… I can now debug the game with breakpoints and have made some changes here and there (albeit very small ones!).

    I have a question, perhaps this needs to be in the modding section forgive me…

    I have a requirement to make the game work so that the cross-hair that always appears in the middle of the screen actually moves around the screen and can be used to aim at objects. So, in essence the mouse would control the ‘hand’ of the player and would not change the players orientation (‘head’ position).

    I’ve found the code where it’s possible to comment out the bit that moves the orientation of the player via the mouse… which is a start… but I have no idea how to get the cross-hair moving around the screen … Would it need to be an entity that’s drawn on the screen and moves according to mouse movement? Then every time a weapon was fired you’d pass it’s coordinates in as what you were firing at?

    Any help to push me in the right direction on this would be greatly appreciated!

    Thanks again for doing this work, it’s really opened up a new world for me here.

    Cheers,

    John

  68. gregd1024 said

    Chris,

    Oh no, it’s definitely not a _rewrite_ to C++, it’s a _port_ to C++/CLI .NET – meaning, everything in the original codebase that needed to be changed for compiling in the C++/CLI environment and ultimately creating a .NET executable have been changed. Since a lot of stuff from the C language was incorporated into C++, many blocks of code remain unchanged. Doing a rewrite to C++ would involve the same amount of effort and time as doing a rewrite in C# – I’d rather do a C# port, so I’m saving my energy for that project. πŸ˜‰

    A lot of the code changes are not immediately obvious. For example, C is a weakly-typed language whereas C++ is a more strongly-typed language. In C, you can do an XOR operation on a variable to flip its state between true and false regardless of that variable’s type, such as:

    typedef char BOOL;
    int value = 1;
    BOOL qtrue = 1;

    value ^= qtrue; // value is now 0
    value ^= qtrue; // value is now 1
    value ^= qtrue; // value is now back to 0

    In C++, you can only do this if “qtrue” is the same type as the variable you’re flipping. If it’s not, you either have to use regular “if-else” logic, or typecast the right operand. In the Q3 source, there were some places where doing a typecast was not appropriate and I had to expand it into “if-else” logic.

    Type compatibility was also a big thing going from C to C++. You’ll find hundreds (probably thousands) of typecasts that weren’t in the C source.

    Also pointer manipulation with mixed types you can do in C because it assumes a default type for you. This is illegal in C++, so there were many places where I had to figure out what the default type should be and then use a typecast or change the type of a variable (or group of variables) depending on which way would result in less repetitive typing. πŸ˜‰

    Another not so obvious code change was the fact that John Carmack used variable names that were keywords in C++ but not C. Such as “new”! I think there were something like 2,000 lines that used a variable called “new” which I had to change to some other name.

    Going from native C++ to .NET C++/CLI was also a big thing. Again, there were keywords in C++/CLI used as variable names, such as “generic.” C++/CLI is more strongly typed than native C++, so that generated a lot of compile errors. Then there were some things that simply didn’t work in C++/CLI for some unknown reason. I’d debug for hours, find whatever block of code was causing the problem, rearrange some logic, and then suddenly things would work. Go figure! There was even one block of code which I removed entirely, but it didn’t seem to have any negative effect on the game (this code was doing sound processing).

    While these changes aren’t an all inclusive list, since there were many others, I hope you now have a better idea of what my ported codebase is all about. πŸ™‚

    So to answer your question, no it’s not a pure C++ rewrite – in that case, I’d change all the structs to classes and use some object oriented design. But it is a C++/CLI port so the executable is true CLI bytecode. You can use “ildasm” on the “quake3.exe” file and disassemble the executable.

    -Greg Dolley

  69. Matt said

    Greg, if you want to start a C# port. I’d be willing to assist. I’m sure others would too.

  70. gregd1024 said

    John,

    I’m not clear on how you want the cross-hair moved on the screen. Do you want to have a linear relationship between the mouse movements and the cross-hair bitmap (just like a 2D game)? Or do you want the cross-hair to appear on whatever object the weapon’s trajectory-line intersects first? In other words, do you want it to act like a laser-pointer shining on a wall?

    -Greg

  71. gregd1024 said

    Matt,

    That’s awesome. Let’s talk more. Please email me privately through my Contact page. Thanks.

    -Greg

  72. John said

    Hi Greg,

    Sorry to take so long to reply.

    Well, after looking through the code a bit more, I managed to get the crosshair moving in a linear fashion as you stated in your comments. Basically I realised that the crosshair was moving in the cGame, ie. on the client but not on the server.

    What I’m trying to achieve is having an entity that exists on the server (lets say it’s in the shape of a hand for arguments sake) that will be controlled by the users mouse. So, in effect you could move the hand and if it ‘touched’ a wall or something else an event would be raised.

    I hope that makes some sense? Any help is appreciated!

    Thanks,

    John

  73. Brian said

    Hello Greg,

    Great job working on this, it must have taken quite a while.

    I’m having the same issue as Enrico was where quake 3 can’t find the default.cfg file when the game tries to load in console. I am pretty sure that I have the full version of the game (since it isn’t 46MB it’s a few hundred megs(+/- some mods that I have installed)).

    I’ve tried moving my baseq3 folder into the /code directory and the game loads… but it doesn’t completely work correctly (missing items from menus, random freezes, etc.). I figured since it was looking in the C:\quake3\code directory for ‘baseq3’ I may as well try it.

    Thoughts? Ideas?

    Thanks,
    Brian

  74. gregd1024 said

    John,

    I think you’re forgetting one very important factor. How far away is the “hand” from the camera/player’s viewpoint? Can it move closer or farther away? In order to determine whether the hand has hit a wall, its z-coordinate will have to be considered. If you somehow allow the user to control the z-depth (maybe with the mouse wheel), then you have enough information to calculate the trajectory vector from the camera to the hand. I know there’s an existing function (probably starts on the client and ends up in the server code), that takes a 3D vector as an argument and returns what entity the vector would have hit (either another player, a wall, sky, etc.). You may want to look into this.

    -Greg

  75. gregd1024 said

    Brian,

    That symptoms you describe come from Q3 not being able to find the game DLL’s. If it couldn’t find default.cfg, you wouldn’t even get in the game at all – it’d simply error on that blue startup dialog.

    First off, you don’t need the “code” directory in the quake root. I keep my code in a totally different directory, even on a different drive. So I’d move the code directory out of there just to avoid confusion.

    Second, try copying the three game DLL’s (qagamex86.dll, cgamex86.dll, and uix86.dll) into “c:\quake3” and “c:\quake3\baseq3.” The quake3.exe should be under the root (c:\quake3). I suggest copying to both places because the Debug build looks under the root, while the release build looks under “baseq3” for those DLL’s.

    The last, and most important thing, is to set the command line parameters when launching quake3.exe. Remember, Q3 does _not_ load mods by default and even if you don’t change anything in the code, it’s still considered a mod (because the newly compiled code isn’t in the original pak files). So you _must_ add these command line arguments:

    β€œ+set sv_pure 0 +set vm_game 0 +set vm_cgame 0 +set vm_ui 0β€³

    So if I were to run Q3 from DOS, the full command line might looks like:

    c:\quake3> quake3.exe +set sv_pure 0 +set vm_game 0 +set vm_cgame 0 +set vm_ui 0

    If you’re launching from Visual Studio, make sure “c:\quake3” is set to the working directory and that those command line arguments are also set in the “quake3” project of the solution.

    Hope this helps! πŸ˜‰

    -Greg

  76. Roman said

    Greg,

    I donwloaded your source code and I don’t see single managed class in the code you “ported to managed code”. Can you point me to any class in the souce code which uses __gc or __value keyword which is necessary to create a .NET managed type. What objects/memory in ported code is managed by .NET garbage collector?

    What I think you did is that you created a mixed asemblies ( see http://msdn.microsoft.com/en-us/library/x0w2664k(VS.80).aspx ) which I believe contain mostly “unmanaged machine instructions” and no managed code apart from what Visual Studio compiler links into mixed assemblies by default.

    Or am I missing something?

    It is an interesting experiment – but sorry – I don’t see managed code there …

    Thanks,
    Roman

  77. gregd1024 said

    Hi Roman,

    You’re forgetting that the original source code didn’t have any classes to begin with – there aren’t any classes in C, so there are no objects for the GC to manage. I think what you meant to ask was: why didn’t I convert all the struct’s to ref’s? Simple: pointer arithmetic is done on virtually every type at least once somewhere in the code. You can’t do pointer arithmetic on managed types unless you use a pinned pointer or interior pointer. But therein lies the problem: you can’t declare a pin_ptr or interior_ptr on an entire object, just members of the object (don’t confuse this with the object’s handle – you _can_ declare a pinned pointer on an entire object’s handle, like: pin_ptr – but this still doesn’t do you any good; you need a byte pointer into MyClass’s managed memory space). And rewriting every part of code such that it doesn’t require pointer manipulation would be akin to rewriting the entire codebase.

    I think you were under the impression that this port was a /clr:pure project. No way. My goal was _not_ to prove that I could convert every struct into a managed class. My goal was to get the quake3.exe and dll’s to compile in regular /clr mode (and therefore see them disassemble in ildasm). Once that worked, then I could access all the .NET framework and make an extension mechanism that would allow other .NET modules (written in C#, or VB.NET, or whatever) to be plugged in and extend the game. (For those who are wondering about this – I have started the extension mechanism, but due to an increase in the time involved in my other project – “making a living to pay bills” – my progress on the extensions has been very slow.)

    If anyone has the time to convert every struct to ref’s, take out all the pointer arithmetic, convert all native-style arrays to managed “array’s”, etc. then it’s better to do a port directly to C# – it would take about the same amount of time and, in either case, 90% of the code would have to be rewritten.

    About mixed assemblies: they’re definitely not native machine instructions mixed in with a little managed code. It’s actually just the opposite – mixed assemblies is the default type (/clr) if you start a C++/CLI project from the wizard. The compiler will try to make everything IL code, even native types, and if it can’t, it’ll thunk it to native. To force the compiler to make everything IL code and only do native thunking for native DLL calls, you use the /clr:pure option. To force absolutely everything to IL (not even native DLL calls are allowed), you use /clr:safe.

    I suggest you take a look at ildasm’s output for quake3.exe or any of the three game DLL’s.

    Btw, __gc and __value are for the old “managed C++” syntax which will no longer be supported in the next version of Visual Studio. Every program written with this old syntax will need to be rewritten because Managed Extensions for C++ is being removed. C++/CLI (supported in VS 2005 and up) has .NET built into the C++ language. Here’s an awesome conversion guide: http://msdn.microsoft.com/en-us/library/b23b94s7(VS.80).aspx πŸ˜‰

    -Greg Dolley

  78. ac said

    Native structs get converted in clr:pure to this (only in clr:safe you’d need to hand modify them)

    [StructLayout(LayoutKind.Sequential, Size=40), DebugInfoInPDB, NativeCppClass, MiscellaneousBits(0x41)]
    internal struct some_c_struct
    {
    }

    I’m not sure how it works under the covers, instead of metadata there’s some custom table lookup thingy being used from the little I could understand with quick look in the spec.

    Most of the work I had going from /clr to /clr:pure was resolving few ambiguous refs that came up in linking and adding some glue for callbacks going into C-libraries. The “implicit pinvoke” ijw interop thingy works great except for when you create function pointer in clr:pure code, pass it to native lib that then calls it. It took couple additional lines of code per callback to clue the compiler into what was supposed to happen.

  79. Naffluema said

    Brilliant!

  80. […] Now that’s pretty cool…  A .NET port of the Quake 3 Arena source code. […]

  81. kebabbert said

    Wow, this is cool man. How is the performance under .NET compared to pure C++ exe? Do you have any benchmarks with FPS? That would be interesting!

  82. gregd1024 said

    Hi Kebabbert,

    Sorry for the delay. Been too busy….

    Anyway, yes, I have some stats. I posted some numbers in an earlier comment a few months ago. Here’s a quoted portion that contained the FPS info:

    ————–
    “…I ran timedemo’s without vsync and turned off the fps cap. Here are the numbers (this is from demo β€œfour” that comes with the Ultimate Quake box you see in stores). I ran each instance three times to make sure there weren’t any flukes:

    Running original Quake III commercial game:

    Test run #1: 324.2 fps
    Test run #2: 330.9 fps
    Test run #3: 332.5 fps

    .NET port:

    Test run #1: 328.6 fps
    Test run #2: 336.9 fps
    Test run #3: 336.8 fps

    At first it may seem weird that the .NET version is slightly faster, but remember, the original commercial quake3.exe uses its own custom interpreter to run QVM files responsible for all of the game logic (except rendering of course). My .NET port uses DLL’s also _interpreted_ by the .NET framework instead of QVM’s. So what you’re really doing is comparing who’s interpreter is faster.”
    ————–

    So, in other words, there’s really no way to get an apple’s-to-apple’s comparison given that the retail Quake 3 game uses QVM’s instead of DLL’s. If you were to recompile the retail Quake 3 source and disabled the QVM’s – using pure C++ DLL’s only – then it’d be a fair test.

    -Greg Dolley

  83. Z said

    YAY! This is so cool, a C# port is cool too with capabilities for other rendering API like XNA,SLIMDX,TAO in windows and MONO+TAO in LINUX, ;)).

  84. Very nice work, Greg! I love it! Still a goog game πŸ˜‰

  85. LiquidMeTal aka Killz said

    Guys i would like to inform all of you about a new release quake 5 arena!!!!!!!! coming soon march 2010 all same weapons better graphics new maps new feel to the game its going to be amazing.

  86. wemheuer said

    Download Link down?
    Is there a mirror?

    • gregd1024 said

      Yes, it’s down. I’m moving servers, but my new provider is taking a while to set up the new hosting account. Go to my Contact page and send me an email. I’ll reply with the zip attachment.

  87. gregd1024 said

    Sorry for the late reply. It’s up now πŸ™‚

  88. Owen said

    Hey Everyone,

    When I seem to run the game on another computer without VC++ 2008 on, It doesnt seem to work. I get the error “This application configuration is incorrect.” Or something similar like that. Some people solved this problem they said, by installing the Redibs Package, But when i installed it and Re-booted, It showed me the Exact same error. I even tryed installing VC++ 10 on and it still showed me the error.

    I’ve posted in numerous forums, but people are just saying “Oh, your making a game!?” Like what the hell?

    So I was wondering if someone on here had the common sense to help me out, without saying the bit on the quotes.

    Kind Regards,

    – Owen.

  89. […] Dolley has finished the Quake 3 Arena .NET Port! The retail copy of Quake III is needed to run this source, it does not work with a demo version. […]

  90. Vlad Fedoniuk said

    Hi Greg! Do you have any info about common architecture of game? Thanks

    • gregd1024 said

      Vlad – hmmm, common architecture, that’s a tough question. Besides the graphics engine part, the rest of the game code is really just a code interpreter that’s designed to run mods. The original Quake 3 game is in itself just a mod. That’s why you see little variants of Q3, such as capture the flag, that can change the original game without using a different exe.

      -Greg Dolley

  91. Johnny Piette said

    Hello Greg,

    I try to compile your solution with Visual Studio 2010 and with DirectX SDK of february 2010.

    VS2010 did a conversion of the project with this result: http://djoni.be/uploads/UpgradeLog2.XML

    I’ve a lot of warnings when I try to rebuild the solution: http://djoni.be/uploads/warnings.txt

    I hope it will help u πŸ™‚

    Regards,

    John

  92. Gedichte said

    Hello from Germany! May i quote a post a translated part of your blog with a link to you? I’ve tried to contact you for the topic Update: Quake 3 Arena .NET Port is Done! Β« Greg Dolley’s Weblog, but i got no answer, please reply when you have a moment, thanks, Gedichte

  93. mREZA said

    i get this error – before loading levels :
    ‘user interface is version 3, expected 6’

    ——————————————

    For people get default.cfg missing error :
    *.PK3(s) are archive file, you can extract em by 7zip or winrar
    default.cfg file is in ..\baseq3\pak0\ Directory

    make sure ‘cgamex86.dll’ and ‘qagamex86.dll’ and ‘uix86.dll’ are compiled successfully and placed in C:\Quack3 folder

    run quake3.exe from C:\Quack3

    OR

    for run game directly from visual studio :
    copy whole ‘baseq3’ folder from C:\Quack3 to ..\Quake3_Arena_VC9_NET_MCPP_Port\code
    then run game by pressing ‘Start Debugging’ button in visual studio

  94. Ruirize said

    This is supposed to use DirectX, is it not?

    Then why am I still getting errors about the loading of OpenGL?
    This is worrying seeing as I don’t have a card that supports OpenGL.

    😦

    • gregd1024 said

      No, Quake 3 uses OpenGL for graphics. The only DirectX being used is for keyboard/mouse/peripheral input.

      -Greg Dolley

  95. Rolf said

    This looks really cool, but… the download link of the source code is down. 😦

  96. Nemo said

    Greg can you please reupload this? I’d love to take look πŸ™‚

Leave a comment