Quake for iOS and tvOS for Apple TV

OK, so my next stop on my tour of the id Tech engines for iOS and tvOS is Quake, powered by id Tech 2. Again for those who would like to cut to the chase, here’s the GitHub repo:

Quake for iOS and tvOS for Apple TV:

Unlike the previous two games, Wolfenstein 3-D and DOOM, this game, Quake, did not already have a version on the App Store. id Software had never ported it themselves to iOS, so there’s a different set of challenges and issues. Like before, I was able to leverage the work of others but unlike before, there was not a concern of minimizing differences from the last known version.

First, some nomenclature notes. For several years, in general, the engine id Software would write for a game had no formal name other than the name of the game it was written for. So, DOOM was powered by the DOOM Engine, Quake was powered by the Quake Engine, etc. It wasn’t until the 2007 unveiling of Rage that id Software unveiled a new naming scheme: “id Tech”, and Rage was powered by id Tech 5. The DOOM 3 engine, then, was retroactively named id Tech 4, and the Quake III engine was retroactively named id Tech 3.

However, at least initially, there wasn’t any official designations prior to that. Clearly, Quake II would be id Tech 2 but what was the original Quake? If you consider Quake to be id Tech 1 then DOOM would be id Tech 0 and then Wolfenstein 3-D would be id Tech -1 and that would just be kinda silly.

Anyway, the consensus on Wikipedia at least is that Quake, QuakeWorld (an internet optimized multiplayer version of the original Quake) and Quake II are collectively considered to be id Tech 2 since while Quake II‘s engine has significant differences over the original Quake, it’s still ultimately an evolution versus a clean slate.

So that would mean that DOOM is id Tech 1 and Wolfenstein 3-D is id Tech 0. This is sort of like hammering out which six versions of Windows prior to Windows 7 “count” towards the number but I can live with it.

So basically it would go something like this

Engine Year id Games
1991 Wolfenstein 3-D, Spear of Destiny
1993 DOOM, DOOM II, Final DOOM
1996-1997 Quake, Quake Mission Pack 1: Scourge of Armagon, Quake Mission Pack 2:  Dissolution of Eternity
Quake II, Quake II Mission Pack: The Reckoning, Quake II Mission Pack: Ground Zero
1999 Quake III: Arena, Quake III: Team Arena
2004 Doom 3, Doom 3: Resurrection of Evil, Quake 4, Doom 3 BFG Edition, Enemy Territory: Quake Wars, Wolfenstein
2011 RAGE, Wolfenstein: The New Order, Wolfenstein: The Old Blood
2016 DOOM (2016), Wolfenstein II: The New Colossus

These aren’t official logos, by the way. RAGE was launched with an “id Tech 5” logo on the back of the box and DOOM (2016) was launched with an “id Tech” logo on the back (no number) but I figured out what they did with the Impact font so I went nuts with it.

Anyway once I got done with updating the existing ports of Wolfenstein 3-D and DOOM for iOS 11 I started to postulate on the possibility of doing Quake next for various reasons, not the least of which is bizarre nostalgia.

Quake was released in 1996 as a DOS game. It was technically shareware like Wolfenstein 3-D and DOOM but it was pretty much at the tail end of where shareware existed as a concept and just morphed into demos. Part of the appeal of shareware was just what it said – the idea of sharing with others. The shareware version of Wolfenstein 3-D could fit on a single floppy disk (and, depending on who did the release, the full game could fit on a floppy disk as well, though there appears to be at least one release that spread to two disks). If I recall right, DOOM shareware could fit on two floppy disks and the full game took up four. One or two floppy disks was not too bad when you were sharing games (as in, literally taking disks to someone else’s house or copying them for others) . Quake‘s shareware, however, took up seven floppy disks and the full game wasn’t offered on floppy disk at all, a first for id, both because of the size of the game and also because the Redbook Audio CD soundtrack from Trent Reznor was a big part of the game. Seven floppy disks was pushing it in so far as convenience is concerned, especially since anyone old enough to have used them remembers their tendency to go bad with invalid sectors and having something on seven floppy disks just increased the odds of that considerably.

I don’t remember what came first, the release of Quake or the introduction of consumer-grade 3D accelerator hardware but after launch there were a few different additional versions of Quake released, all as executables (as in, you still had to have the DOS version of the game for its files but you could drop in these executables alongside the DOS binary). There was QuakeWorld, which was optimized for Internet play with client side prediction (Quake had been designed to send everything over every frame over a wired LAN or T1 connection, this proved daunting to the rest of the world on 56k modem connections, so QuakeWorld tried to minimize the need for this). There was WinQuake, a version designed to run in Windows 9x (an idea that seemed a little crazy at the time due to the performance hit Windows introduced).

Then there was VQuake, for the Rendition Vérité chipset. I actually remember reading an article from PC Gamer where when asked what 3D accelerator to buy they said “we have no idea whatsoever, but John Carmack is making a version of Quake for the Rendition Vérité so based only on that, we recommend that.” Yeah, I appreciate their logic and they were up front about having no idea but since most people don’t even remember that Rendition existed or what a Vérité was, clearly turned out to be wrong.

The story goes Carmack hated working on the Vérité version both because of its proprietary API and also because that API was horrible to work with, so he decided the next hardware renderer he did would use a non-vendor-specific API. The first one he tried was Direct3D, the 3D rendering portion of Microsoft’s DirectX, but he got fed up with it quickly. This was in 1996 so it had to be version like 1.0 or 2.0 or something. He remarked that it took pages and pages of code to achieve what OpenGL could do with a few lines so he decided to go back to OpenGL (not sure if that means he had experimented with OpenGL before or if he had done OpenGL in a previous gig for some reason).

The result was GLQuake. They would go on to release several versions, culminating in version 0.97. It never did officially see a version 1.0, either because they didn’t want to send the signal that they were officially supporting this version or because they just never got around to releasing it (more on this later)

Parallel to all of this, Quake was released initially as version 1.00 in shareware, followed just a day or so later by a version 1.01 which included some bug fixes and joystick support, which was not in the first version (joystick in this case meaning something plugging into the Game Port on the back of old PCs or sound cards, USB controllers would be a few years out). Version 1.01 is what would wind up shipping on the disc for people who ordered it in the mail from id Software – 1.00 never got a full release in any form and only OCD weirdos like me remember this. Later, a patch to version 1.06 got released with some more bug fixes and features.

Quake got two expansion packs, the first was called Quake Mission Pack 1: Scourge of Armagon and it was done by Hipnotic Interactive, which would go on to be renamed Ritual Interactive for reasons too trivial for Wikipedia to even remember. It shipped with version 1.07 on the disc. The big innovation in 1.07 was the addition of rotating brushes (walls and things could rotate) and they made sure you knew it with the beginning of the very first level. The second expansion pack was Quake Mission Pack 2: Dissolution of Eternity by Rogue Entertainment and it shipped with version 1.08 on the disc. Finally, a patch to version 1.09 was released, independent of an expansion pack, and this is the last patch Quake ever received.

The follow-up game, Quake II in 1997, would ship with software and hardware renderers out of the box, and then Quake III: Arena would ship with only a hardware renderer.

Shortly after the release of Quake III: Arena, id released the source code for Quake as open source under the GPL license. You may recall from my previous long winded article that they had some issues with the initial release of the DOOM source code so they just went GPL from the get go with Quake.

In the code, people immediately noticed it contained what appeared to be GLQuake 1.0 and id Software did indeed confirm that this was the never-released 1.0 version. I don’t know what, if any changes there were between 0.97 and 1.0 but in any event there it was. Quake would display two version numbers, the game version (i.e., 1.09) and the GL renderer version (i.e., 0.97) so that’s how they were able to coexist.

In my previous writeup, I remarked that the Internet didn’t seem to care about Wolfenstein 3-D‘s source code being released but they went absolutely nuts over DOOM‘s source. The reaction to the release of the Quake source code was somewhere in the middle, for various reasons. Quake was never as big as DOOM, at least to the casual mainstream gamer. I mean, Quake was big but DOOM was a cultural phenomenon.

Gameplay-wise, Quake was all over the map. The book Masters of DOOM elaborates on it further but the development of the game was troubled – it took longer than anticipated, the staff clashed over disagreements over direction (eventually leading to the firing/quitting of John Romero), and the concept and theme of the game changed a few times. Early discussions and interviews with id indicated that Quake was to be a different kind of game at one point – lots of melee weapons, small enemy counts, no music, and more of an intimate experience. Late in development most of those elements were stripped out.

The result was, in many ways, a polygonal version of DOOM, as in “guy with gun runs around and shoots things”. There was no real cohesive vision to the single player of the game – one level takes place in a space dungeon, another takes place in a medieval castle, complete with sword-wielding knights. The final boss is a giant multi-tentacled monster seemingly influenced by Cthulhu, and indeed the entire world has a sort of trippy skybox sky thing happening with a Lovecraftian vibe. And that’s not even mentioning the fact that the manual implies that before you start out your adventure, “You have full authority to requisition anything you need” and you start the game with one crappy gun and very little ammo.

This may sound like I’m bagging on the game, I’m not, I actually liked the game quite a bit and I still do. The bizarre lack of cohesion was popular enough that there’s still people who want a direct sequel to this concept (the later Quake games had no connection to the original in terms of plot, it’s very nearly an anthology series other than Quake II and Quake 4 sharing a universe).

And then there was the multiplayer and mods. QuakeWorld allowed for play over the Internet, complete with quickly abandoned concepts like online clans. For the first time id officially supported the concept of modding, complete with a release of a subset of the original source code, which may have been unprecedented. The concept was that the “rules” based source code could be compiled into its own distributable binary blob, and the main Quake executable read it in and used it. It’s like a DLL file in Windows, except Quake was a DOS game and DOS didn’t have that concept. So id came up with a language called QuakeC and a compiler for it – basically rolling their own DLL concept. This is the thing people went nuts with. People came up with new modes and new concepts and even basically new games. The concept of a “Total Conversion” became a thing since you could now officially change the graphics, models, sounds, levels and code. You could, if you were so inclined, make essentially a new game in every respect other than you couldn’t sell it and it required Quake to be installed. Many of these got started, a fraction of them ever finished. But mods like Capture the Flag got its author hired by id Software and mods like Team Fortress later became games with sequels by companies like Valve.

In many ways Quake wasn’t just a game, it was an industry, and it got a lot of careers off the ground.

So having said all of that, here’s my weird nostalgia: I had Quake as soon as it came out and I was a big player of it on my Pentium 90 with no hardware acceleration because it basically didn’t exist yet. I had it in college and I was all about mods and so forth. And then my friend a few doors down who was a Macintosh guy finally got it and got to play it because they released it for the Macintosh. I kinda remember it blowing my mind seeing it run (optionally) in a window (this had to be before WinQuake). Also kinda blew my mind that it was the exact same game – this is the console Kool-Aid Man era where it was common for the same named game across multiple platforms to have radically different versions, but here was Quake playing the exact same on the Macintosh – I think it may have even had cross-platform multiplayer but don’t quote me on that.

So a few years ago when I came over to The Dark Side and became an Apple/Mac guy, I somehow remembered this thing in the dorm and I thought it would be fun to play Quake on my Mac all these years later. Thanks to a lot of reasons, not the least of which was the processor and operating system differences, obviously I couldn’t play the exact same version as that time in the dorm but this thing’s been open source for a while now, surely it’s possible, right?

Well, none of the official channels for buying or playing Quake – namely Steam and GOG – feature Mac support. In fact I think at least Steam is still actually playing the DOS version, or maybe WinQuake. What I’ve found is the case sometimes with these old games is that they don’t want to make something new they’d have to support and since it would take effort to make a macOS x64 version of Quake, it doesn’t happen. I can’t blame them, the old shipped-decades-ago version is the devil you know.

So what you have to do is get the files from the Steam/GOG/DOS version on your Mac and then find a source port. And like a number of things, you have a much easier time finding a Windows port than a Mac port, a phenomenon no doubt related to the operating system and architecture changes the Mac has seen since 1996 (2001 being the switch to Mac OS X from classic Mac OS and 2005 being the Intel switch).

As luck would have it, the first port I found was called Quakespasm. I was skeptical when I found it, both because the website still has the same sort of weird brooding look and feel you’d expect from a 1996-era site, but also because the README file went into extreme detail as to the twenty steps needed to compile on the Mac, including hunting down Xcode 5 or something (we’re up to Xcode 9 now). There was also an Xcode project file named such that it was still designed to be built on the Power PC Macs.

I looked at a couple of other ports and came back to Quakespasm. Luckily the README file was just horribly out of date – it builds and runs perfectly out of the box with no changes in Xcode. So there I had it – Quake running on my Mac(intosh).

While I was looking around I also found a source port called DarkPlaces that interestingly did not have a Mac Xcode project file but it did have one called “DPiOS.xcodeproj” which I took to mean it was an iOS port, but it didn’t build.

And then I found one called Quake_For_OSX. This one was really interesting because it was done by someone who clearly knew what they were doing, but did nothing the usual way. It was designed by someone after my own heart – it had macOS, iOS and tvOS targets. Except, interestingly, the macOS and tvOS targets were of the software renderer version of Quake but they used Metal to render to the screen (compared to Quakespasm which used the GL renderer), and the iOS target did use the GL renderer – but only in the context of Google’s Cardboard VR SDK.

Yeah – this guy had shimmied the Google Cardboard VR SDK into Quake, so you can play Quake in VR. You had to use an MFi controller or else you couldn’t play the game (makes sense, it’s not like you can touch the screen while it’s in your viewer). Long story short I had to try it out – I bought one of those $5 VR headset things from Walmart (what a time to be alive) and fired it up

What was I going to do, NOT buy the VR viewer that kinda looks like the Virtual Boy?

If you find this concept interesting I recommend you fire this port up and give it a shot. My experience with it was that it was a neat concept and he executed it well, but it has basically all the issues and trappings of adding VR to a game not designed for it. And since Quake is old enough to drink, it’s really not designed for it. He avoids the need for any sort of UIKit shenanigans by just using the intrinsic built-in menu system from the Quake code. He actually had it published on the App Store at one point in time under the name Slip & Frag, and it was a “bring your own PAK file” sort of affair (I think the average person was supposed to get them on there using iTunes. Seriously) but it’s not on there anymore – not sure why but it could be he just didn’t renew his Apple Developer account.

So that was a few years ago. Then I got the wild hair to fix up Wolfenstein 3-D. And then DOOM. And then put them on Apple TV as well. And then I got the idea that it would be cool to do Quake next. The fact that there never was an official id Software port of Quake to iOS was both good and bad – bad in the respect that it’s not a matter of just sprucing up code I know worked on iOS at one point, good in the respect that I didn’t have to worry about minimizing the number of changes I made. No pull requests here.

It should be obvious by now that the value I bring to these concepts is not a deep knowledge of 3D graphics programming but rather the ability to pull shit together and know the other kinds of details to get crap running on Apple platforms – like how AutoLayout works and how to use Cocoa Touch and navigation controllers. But with no official id Software port to work with, after assessing all the stuff I knew and remembered from when I looked for a Mac source port, I had basically four options:

a) Use the Quake_For_OSX port for iOS and strip out the Google Cardboard part.
b) Use the Quakespasm macOS port and figure out how to get it to run on iOS
c) Use the DarkPlaces iOS port and fix whatever’s broken in it
d) Use the original Quake source code drop and figure out the whole thing from scratch

After some debate I decided on the Quake_For_OSX approach. As a bonus it uses Swift for the non-C parts, which is so much nicer than Objective-C and dealing with header files it’s not even funny.

It took a few passes to figure out how to remove the Cardboard SDK but I figured it out. The SDK featured a view controller delegate that would handle rendering to the screen as well as when certain things were known. On a real basic level, Quake runs in a loop with a function called Sys_Frame() just being called over and over until you exit. The author of the port had to split that up into three different methods in order to be able to pass in position information from the SDK as it was given to you.

The Wolfenstein 3-D and DOOM ports were done with a class called EAGLView which looks to be derived from an example Apple came up with to show how to show OpenGL content on the iPhone screen using OpenGL ES. Starting with iOS 5, Apple provided something called GLKit. Its equivalent of EAGLView was called GLKView, and it even provides an GLKViewController to handle GL content in a similar fashion to how UIViewController contains everything within a root UIView. I ultimately decided to use this but it was a weird process learning it and figuring out how to transition to it. My basic following of it is that the game engine writes to a GL “context” and the GLKViewController puts whatever’s in that “context” to the screen. I kept looking for some sort of “here, here’s the context” argument to some sort of method and there just wasn’t one. Even as I write this I’m not 100% clear on what the connection is, or where the “context” truly resides, all I know is that at some point I got it working.

At some point when I figured out the connections needed to get the Sys_Frame() method called at the right times I could hear sound effects from the opening demo playing and I could see things like “You got the shells” flying by on the debug console so the game was “running”, I just couldn’t see anything. Once I finally got everything set up and the GL context knew where to draw the frame and what size I got it running and I saw stuff on the screen and it was glorious… until I realized that everything was fucked up and wrong.

Ah, that’s one fine looking Quake level WHY DOESN’T MINE LOOK LIKE THAT?

Yup, it was running full screen, and full speed, and everything sounded and handled right, it was just all jacked up and broken. And just a little bit broken, which I figured was worse because I was afraid that it would mean I’d need to dig in and fix 3D rendering code and I really have no idea how to do that.

In addition to getting it running in Cardboard VR, the author of the Quake_For_OSX port also did some amount of work to convert the code to OpenGL ES 3.0. In the Wolfenstein 3-D port there was a file called gles_glue.c which basically functioned as a bridge between OpenGL ES methods and their OpenGL equivalents when necessary. This author, however, had gone in and rewritten large swaths of code and imported new concepts, like compiled shader programs. I am still ignorant on what shaders do exactly but you see that term used a lot. So it wasn’t like I could go in there and just see what minute tweaks he made because there weren’t any, there were just massive changes. My theory was that he had to do something to the code to make it play nice with Cardboard VR and I just needed to tweak that differently. I had a sinking suspicion that it was one of those deals where the fix was one line of code, I just had no idea where.

The hell of it was I had a basically working version in the respect that you could tell the Cardboard View Controller to stop doing VR and then it just renders the game normally. I considered the idea of just repurposing the Cardboard version and just having VR be in there as a bonus but I really didn’t want to have external dependencies if I could avoid it. The Quake_For_OSX port includes the Cardboard SDK via CocoaPods, a popular package management solution for Xcode projects that I haven’t had much luck with, plus there’s some indications that Google may have abandoned the iOS Cardboard SDK, so I didn’t want to hitch my wagon to that.

I started considering other options. I started trying to get Quakespasm working in iOS but besides the fact that a lot of the work to get OpenGL and OpenGL ES bridged would have to be done or re-done, Quakespasm also uses SDL and I really didn’t know enough about SDL to know how to get it running on iOS. It’s bizarre, when you start dealing with C/C++ stuff you wind up going down this rabbit hole of code that’s worked a certain way for decades, and websites with downloads that haven’t been touched in years, which is both good and bad – good in that the things you’re dealing with are mature and evolved, bad in the respect that you’ll see that they got SDL2 working in iOS 5 and Apple’s so not afraid of breaking shit that it’s a toss-up if it works anymore or not.

So I tried to take another look at DarkPlaces which unlike Quakespasm wasn’t building at all but at least it has an iOS project file. But I tried getting it to compile and it has issues. Like, massive issues. It’s possible I just didn’t have some dependency set up right but I really think it’s that the iOS project file is just badly out of date. When you’re dealing with an open source project that predates things like GitHub it can be hard to figure out if what you’ve found is the actual project or just someone’s mirror but it looks like the iOS project file had seen an update back in May but the previous change to it was in 2013 or something. I’m not sure how it could have been updated so recently and still not build unless someone’s maintaining it with an old version of Xcode (entirely possible). It looks like the version I had found powers a free online shooter called Xonotic, but that game has no iOS port, so once again it was looking like finding what was wrong with the Quake_for_OSX port I had forked was going to be less effort, plus I had started to see that some iterations of DarkPlaces do things with the engine that people disagreed with.

So it was back to the work I had done before. And then in the middle of all of this, WWDC 2018 happened and Apple announced they were deprecating OpenGL and OpenGL ES on Apple platforms in favor of Metal.

Thanks assholes

I’m kidding, I don’t think they’re assholes, but the part of me that was entertaining the idea of learning some OpenGL ES to figure out where my problem was occurring was diminishing considerably.

They’re still going to have OpenGL support in iOS 12, macOS 10.14 and tvOS 12 but at some point in the future they might disappear. They said anyone who is about to ship something with OpenGL should go ahead and do it but new work should strongly consider using Metal.

Metal is basically Apple’s Direct3D, as in – a proprietary API that no one else uses. it’s true that apps and games that use it on macOS and iOS benefit considerably but at least for now there’s basically no way I’m going to be able to change anything to run on Metal right away. Clearly it’s possible – the other two targets use it – but it’s beyond the scope of my interest at the moment.

The consensus seems to be that Apple will likely leave OpenGL in there, untouched, probably for at least a few more years. So if I ever do get the urge to come back to these projects and convert them to Metal I can do that later but right now it’s not happening.

Anyway I went down a pretty deep rabbit hole with regards to figuring out what the problem was. I was logging like crazy between the working version and my version, looking for what numbers could be different. On some level everything in these engines is math and I was trying to figure out where the numbers were different. I used this source code review and selective commenting out of code to drill all the way down to the method that was basically determining where the actual polygons were being rendered and even after rigging up the two simulators to have the same amount of elapsed time between frames (so that, in theory, they were rendering identically) the numbers still matched up.

I’d rather not admit how many weeks I screwed with this (though in my defense this is purely a spare time thing) but I finally determined that the code of the actual Quake engine was not the issue. I figured it was down to maybe something intrinsic about GLKView/GLKViewController versus the Cardboard view controller.

I started dinking with options that either did nothing or make things worse. And then i found drawableDepthFormat. Changing that to anything but the default caused it to work. I was simultaneously thrilled and annoyed since the tutorial I was following on how to use GLKit talked about it, but it did so in the section I skimmed since I didn’t know what it was talking about.

You can set this property to choose the format of the depth buffer. The default value is GLKViewDrawableDepthFormatNone, which means that no depth buffer is enabled at all.

But if you want this feature (which you usually do for 3D games), you should choose GLKViewDrawableDepthFormat16 or GLKViewDrawableDepthFormat24.

Why oh why was this not set to something useful to begin with? I guess it’s because if you’re using OpenGL to draw 2D objects on the screen you don’t need it.

So anyway it now worked great in the simulator, running the demo. So I tried it on a real device and – it flickered like crazy. Fortunately I figured this one out pretty quick – the code had been set up to not render every frame as every frame because every other frame needed to be duplicated for the other eye. Or something. Anyway once I went in and disabled that everything ran great.

And then on a lark once I was home messing with it I quickly added a tvOS port since we still had no UIKit elements to worry with yet and it not only had MFi controller support, it required it. I got the storyboard with the one GKLViewController going, I tweaked the settings to the project file, I made all the source code files be in the tvOS target as well, and in less than an hour of working with it, I had it running on tvOS. I fired it up in my theater room and I was blowing through the first level in the fourth episode on the big screen. It’s amazing how quickly it worked and how well it played. And nothing like doing this after going through Wolfenstein 3-D and DOOM a lot to make you realize how far the tech and level design had come by the time Quake rolled around.

Plus I had to do my magic with icons again

The big three

So now I had basically the opposite of what I had at this same point in the Wolfenstein 3-D and DOOM ports – it ran on the phone as well as the TV but it was unplayable on the phone unless you had an MFi controller. Whereas DOOM‘s port actually seemed to run the on-screen controls as part of the game itself, Wolfenstein 3-D‘s port rendered them as an overlay of UIKit controls. My first instinct is that DOOM‘s approach was superior, mostly because it had been done later, but the more I looked at it and thought about it, I figured the easiest approach might be Wolfenstein 3-D‘s.

I found some code online where someone had implemented a sticky “joystick” in Swift (sticky in that it went back to the center when you let go) and then added some buttons and once I figured out how to feed the values from the stick into the game engine correctly, I had basically a mostly-playable iPhone version of Quake.


Now we’re getting somewhere

I went in and added some UI to the thing. I added a main menu and the ability to select either the original Quake game or either of its expansions.

Demo included since, you know, that’s how you hear the theme song

Mission Pack 2’s cover art was clearly aping the Sega Saturn marketing playbook

I did go in and add the ability to select which episode, level, etc. but it occurs to me I also needed a way to just “start” the game. Quake does this thing that was neat, innovative, and – near as I can tell – was never done by any other game ever again, not even Quake II – it just starts off the game and you determine your preferred skill level or episode by going down different hallways. They even have a creative thing where you have to do find the secret way to launch Nightmare difficulty. It was ingenious – and if I had omitted it I’d be amiss (plus I think you have to have the Start level to get to the final boss).

Now I needed to get some music going. The Quake_for_OSX port had basically neutered the sound – the code from the original game was designed to fire off the CD-ROM drive’s audio player but since that obviously doesn’t apply to an iPhone, he just deleted the contents of those functions. I had a copy of the soundtracks for all three games in .ogg format from an “Ultimate Quake Fan Patch” for the Steam version. I’m not sure why the person who made that patch went with .ogg but it might have something to do with .mp3 being patent encumbered at the time. That or they were big believers in .ogg which is sort of like being the person who backed Betamax.

Anyway the Quakespasm port had support for OGG as well as MP3 and FLAC and pretty much anything you can think of. There’s even formats in there I’ve never heard of. So I started grafting in the background music code from Quakespasm. This was another interesting rabbit hole to go down, because the code Quakespasm had was designed to read in the contents of the audio files but you still had to have other code to actually play it. Quakespasm contained compiled frameworks for all of these things – but only for the Mac. Any desire I had to bring over support for all of the different music formats faded by the time I had figured out how to get code for the OGG versions working, and I only got that going because the Wolfenstein 3-D port had something called the Tremor library to handle it and I brought that over because I knew it worked.

And then I fired it up and heard no music. I had grafted over all of the code to start playing the music but I still needed to hunt down the code that “painted” the audio samples into the actual game. And then I fired it up after doing that and I heard the music – badly distorted. Like it was a billion decibels through a shot-to-hell speaker. Clearly I was mixing it in wrong but I wasn’t sure where or how. When I got to this point it was very late at night so I called it a day and postulated options – including the notion of just forgetting this whole idea and just having the app play music using the built-in abilities to play music you get with any iOS app. The original game wasn’t trying to sync music to anything, it was just telling the CD player to play a song. I could do something similar.

But the next time I fooled with it, on a lark I grafted in all of the Quakespasm snd_mix.c code, not just the parts that painted in the music, and now everything worked great. I love it when a plan comes together.

Now like I said earlier, there’s different concerns and issues when you’re not working with an existing commercial ports. One of them is knowing how far to go with it – with Wolfenstein 3-D it was simple because the port only had single player because the original game only had single player campaigns. Done and done. With DOOM, the port only had single player so my update only had single player, even though DOOM did have multiplayer itself. The DOOM-iOS port from id did not have multiplayer and neither did the DOOM-iOS2 port, but there was a button on the main form for multiplayer that was hidden and disabled so at the very least they had entertained the concept of multiplayer at one point in time. With Quake, I’ve once again only done single player because it’s the easiest to do (you only need the one device, if nothing else) but while Quake‘s single player campaign was significant, that game’s legs were really in the multiplayer, especially the mods like TF2 and CTF and things like the Reaper bot. I haven’t gone in and neutered the code in any respect but I haven’t the first damn clue what would be necessary to get it working on iOS. To some extent these engines work as well as they do in iOS/tvOS because they use OpenGL and so does iOS/tvOS but they really don’t, they run OpenGL ES, and the Wolfenstein 3-D and DOOM ports have that file called gles_glue.c that basically bridge the differences. It’s possible the built-in networking for Quake could work on iOS but it might need a similar bridging file.

In addition, while Wolfenstein 3-D and DOOM‘s on-screen controls were pretty solid, neither of those games featured the ability to look up or down, or the need to. But I’m not sure the best way to achieve that with on-screen controls for Quake. I could put a second stick on the screen to simulate the MFi controller but that makes firing or jumping problematic because you don’t have, say, triggers on the iPhone by default. I experimented with doing tilt aiming but I haven’t finished that yet and I didn’t want that to hold up the show.

So in that vein whereas I considered the previous ports 100% done to the extent that the goal was achieved (working on modern iOS versions) I’d call this version maybe 85%-90% complete. Both because of the control issue I just mentioned, a few graphic glitches I haven’t nailed down (but nothing that would prevent gameplay) and something else I figured out late in the development.

I thought it would be cool to have the ability to launch Quake or its expansions, complete with box art, and I put that in the app, but I wasn’t able to make it so that you could switch between the three. Quake was designed such that everything gets loaded in on startup, and to some extent the way the app works is like it’s “virtually” starting up the game, but if you were to quit to the main menu and then try an expansion pack it doesn’t work. The expansion or mod or whatever needs to be loaded in on startup, and the original games had different shortcuts installed for that purpose. The code in Quake is designed to close up shop and then shut down the program, but there’s not really a concept of shutting down the program in iOS or tvOS. The things Quake is doing to shut down the program actually cause the apps to crash and even though I’m not aiming to have this on the App Store, that’s still not cool for various reasons not the least of which is that behavior gets your app rejected from the App Store. So like I said it’s 85% complete but until I figure out how to gracefully shut down and restart the engine in-app, you’re going to have to force-kill the thing if you want to start it over.

So, my plan is to continue to work on those things but I figured they weren’t worth holding up the show. I’ll update this article as necessary.

Here are some videos of the ports in action, and how it plays with a SteelSeries Nimbus controller

If anyone wants to contact me I can be reached at tomkidd@gmail.com.