Porting Quake II to MS-DOS pt4

Bringing it all home for release day.

Bringing it all home for release day.

Since the last update we got some help in a few fields that have really fleshed out this ‘experimental’ port into a full fledged port.  First RayerR helped us with the fun of getting us onto the latest deployment of DJGPP, 2.05 (rc1).  It’s always nice to be in the latest available release.  Next in a passing comment, Ruslan Starodubov had mentioned that he had gotten a much older build of our QDOS to support the Intel HDA sound chipset via the  MPXPlay sound library.  I wrote to the author of MPXPlay, Pádár Attila asking for us to distribute his source in our project, and he granted permission.

So at this point things were looking good.  The only ‘feature’ that modern OS’s really held over us was the ability to dynamically load and unload game modules on the fly.  I had tried to use DLM, but it stripped the DPMI functionality out of the MS-DOS Extender making the port really useless.  I tried to build the newer DXE3 support but had no luck.  I suspect now my native tool chain was interfering with the build process. But Maraakate managed to get it to not only build, but to run!

Adding in DX3 support was relatively painless.  I first looked at DJGPP’s FAQ and downloaded the example code.  In the example code there was small helper functions to make unions and check the symbols.  If they didn’t exist a printf was spit out to alert you about it.  To resolve the issue you simply just add DXE_EXPORT to the other list of missing exports.

Compiling the game code was easy, again referring to the example I saw that basically they compiled it the same, but at link time you use DX3GEN and -U flag to ignore unresolved symbols.

The biggest head scratcher was the Sys_GetGameAPI failing to find GetGameAPI from the DX3.  After some piddling around I noticed that it listed GetGameAPI as _GetGameAPI inside the DX3 itself.  I added the underscore and it worked!

Other things that were relatively to easy to import was R1Q2’s HTTP downloading code.  Compiling CURL was kind of tricky because of the linking order, but thankfully neozeed figured it out quickly.

All of Yamagi’s Quake 2 updated game DLLs were all diff’d by hand using BeyondCompare to make sure I didn’t clash using some newer functions that weren’t available in DJGPP.  I also merged their Zaero code with their baseq2 code by comparing Zaeros code to the Quake 2 SDK, marking every thing that was changed.  The result is a really stable Zaero game code.  If you haven’t played Zaero check it out.  I think it’s a lot better than Rogue, but Xatrix is probably my favourite (even over stock Q2).

Other cool things I’m glad to get into the code was the GameSpy Browser.  It took me quite a bit of work to get it where it is, but it’s really nice to just be able to ping to a master server (a custom GameSpy emulator I wrote specifically for Q2DOS.  Source is not finalized yet, but will be available soon for those curious), pick a server and go!  All in DOS!

So here we are at the end of the journey.  Or at least safe enough for a 1.0 release.

To recap, we have:

* VGA
* SVGA (LFB modes only)
* Mouse
* Keyboard
* SoundBlaster and Gravis UltraSound Family
* CD-ROM music
* OGG music
* Networking (You need a packet driver)
* Loading/unloading game DLLs in DX3 format.
* Intel HDA support -hda
* Mouse wheel support with -mwheel

And I should add, that it works GREAT on my MSI Z87 motherboard.

You can download Quake II for MS-DOS on bitbucket.  And as always the source is available here.

Don’t forget you can always make bootable USB stick with DOS, or CD-ROMs.

Continued in Part 5!

Did you know that GCC used to support Windows NT ?

I’m not talking about MingGW, Cygwin or anything else like that, but rather when support for Windows NT first appeared, it had to be compiled with Microsoft Visual C++ 1.0 of all things.

It was back in the 2.6 days of GCC, right before the stagnation that led to EGCS.

`i[345]86-*-winnt3.5'
     This version requires a GAS that has not yet been released.  Until
     it is, you can get a prebuilt binary version via anonymous ftp from
     `cs.washington.edu:pub/gnat' or `cs.nyu.edu:pub/gnat'. You must
     also use the Microsoft header files from the Windows NT 3.5 SDK.
     Find these on the CDROM in the `/mstools/h' directory dated
     9/4/94.  You must use a fixed version of Microsoft linker made
     especially for NT 3.5, which is also is available on the NT 3.5
     SDK CDROM.  If you do not have this linker, can you also use the
     linker from Visual C/C++ 1.0 or 2.0.

     Installing GNU CC for NT builds a wrapper linker, called `ld.exe',
     which mimics the behaviour of Unix `ld' in the specification of
     libraries (`-L' and `-l').  `ld.exe' looks for both Unix and
     Microsoft named libraries.  For example, if you specify `-lfoo',
     `ld.exe' will look first for `libfoo.a' and then for `foo.lib'.

     You may install GNU CC for Windows NT in one of two ways,
     depending on whether or not you have a Unix-like shell and various
     Unix-like utilities.

       1. If you do not have a Unix-like shell and few Unix-like
          utilities, you will use a DOS style batch script called
          `configure.bat'.  Invoke it as `configure winnt' from an
          MSDOS console window or from the program manager dialog box.
          `configure.bat' assumes you have already installed and have
          in your path a Unix-like `sed' program which is used to
          create a working `Makefile' from `Makefile.in'.

          `Makefile' uses the Microsoft Nmake program maintenance
          utility and the Visual C/C++ V8.00 compiler to build GNU CC.
          You need only have the utilities `sed' and `touch' to use
          this installation method, which only automatically builds the
          compiler itself.  You must then examine what `fixinc.winnt'
          does, edit the header files by hand and build `libgcc.a'
          manually.

       2. The second type of installation assumes you are running a
          Unix-like shell, have a complete suite of Unix-like utilities
          in your path, and have a previous version of GNU CC already
          installed, either through building it via the above
          installation method or acquiring a pre-built binary.  In this
          case, use the `configure' script in the normal fashion.

Well that is quite the tall order!  I can’t believe I somehow managed to build it back then, and out of curiosity I managed to build it again.  And as you can see you need a ‘beta’ release of the GAS assembler, which is kind of impossible to find now, but it was part of the GNAT project, which used to distribute binary builds of the GCC core back in the day.  Luckily I have a version stuffed away, although it’s from GCC 2.8.1, not as ancient as it would have when GCC 2.6 was a new thing.   But it at lest assembles enough for my simple Hello World experiment.

To build GCC you need a working SED, which surprisingly CL 8.0 from the Win32s SDK, and it runs fine on Windows 7 x64 of all things.  I had to mess with some of the files, and substitute the linker & headder files from Visual C++ 2.0 but much to my amazement not only can I build GCC along with libgcc.a, it also builds incredibly fast.  On my machine I can compile GCC in about 5 seconds.  I remember in 1995 building this on Windows 95 (I was crazy) and it taking HOURS and HOURS.

So one nice thing about these binaries is that you don’t need any external DLL’s  Even the import section of a simple hello world exe is tiny:

GetVersion GetEnvironmentStrings GetCommandLineA ExitProcess RtlUnwind UnhandledExceptionFilter GetModuleFileNameA GetFileType GetStdHandle GetStartupInfoA VirtualFree VirtualAlloc WriteFile WideCharToMultiByte GetLastError FlushFileBuffers SetFilePointer SetStdHandle CloseHandle KERNEL32.dll

Which implies that it only needs KERNEL32 to function.

I don’t know if it’s of any use to anyone else, but HERE is my dump of all the source and tools I used to build GCC.