cover of episode WipEout with Dominic Szablewski

WipEout with Dominic Szablewski

2024/12/11
logo of podcast Software Engineering Daily

Software Engineering Daily

People
D
Dominic Szablewski
J
Joe Nash
Topics
Dominic Szablewski: 我从孩提时代起就对《Wipeout》这款游戏充满热情,这促使我踏上了漫长的游戏开发旅程。起初,我使用Quick Basic在486电脑上编写游戏,后来转向了更复杂的Windows游戏开发,最终在Steve Jobs宣布iPhone不支持Flash之后,我看到了HTML5游戏引擎的机遇,并取得了一定的成功。在2022年《Wipeout》源代码泄露后,我决定对这款经典游戏进行重写,目标平台包括Windows、Linux、macOS和WASM。重写过程中,我面临着诸多挑战,例如原始代码的混乱、不同平台版本和控制器的差异、以及PAL和NTSC制式的差异。我选择使用C语言进行重写,因为它能够让我更深入地理解程序运行的细节,并享受编程过程中的挑战。在渲染方面,我最初使用了排序表机制来处理PlayStation缺乏Z缓冲区的问题,后来将其替换为更现代的三角形渲染方法。在内存管理方面,我使用了碰撞分配器来避免显式内存分配和释放,这对于《Wipeout》这种具有明显场景的游戏非常有效。尽管重写版本已经发布,但我仍然计划修复一些物理错误,并改进图形效果,例如在隧道中添加灯光效果和更宽容的碰撞响应。我的梦想是能够得到索尼的资助,将重写版本打磨成一个更加精良的作品。 Joe Nash: 本次访谈主要围绕Dominic Szablewski对经典PlayStation游戏《Wipeout》的重制项目展开。Dominic Szablewski是一位经验丰富的工程师、游戏开发者和黑客,他参与开发了Voidcall、Quake VR和Q1K3等项目。此次重制项目基于2022年泄露的《Wipeout》源代码,Dominic Szablewski几乎从零开始重写了游戏,使其能够在Windows、Linux、macOS和WASM等多个平台上运行。在访谈中,我们探讨了Dominic Szablewski的游戏开发历程、重制项目的动机、以及重写过程中遇到的技术挑战和解决方案。我们还讨论了原始源代码的质量、NTSC和PAL制式的差异、PlayStation架构对游戏开发的影响、以及Dominic Szablewski在内存管理和渲染方面所做的创新。此外,我们还展望了未来,探讨了Dominic Szablewski对重制项目未来的规划以及他对其他游戏开发项目的展望。

Deep Dive

Key Insights

Why did Dominic Szablewski decide to rewrite Wipeout in C instead of JavaScript?

Dominic enjoys writing C in his free time because it provides a more hands-on, detailed programming experience compared to high-level languages like JavaScript. C forces him to think about all the details, which he finds enjoyable and challenging.

What was the state of the leaked Wipeout source code when Dominic first saw it?

The source code was described as a mess, with global variables scattered across files, ad-hoc additions for different platforms, and a lack of abstraction. However, despite its poor structure, the game was playable and never crashed on the PlayStation.

What was the main technical difference between the NTSC and PAL versions of Wipeout?

The primary difference was the frame rate. NTSC ran at 60 Hz, while PAL ran at 50 Hz. This required adjustments in the game's physics and rendering to ensure smooth gameplay across different regions.

How did Dominic handle the PlayStation's lack of a Z-buffer in the Wipeout rewrite?

Dominic implemented a modern rendering approach that abstracts the renderer, allowing for easier porting to different platforms. He replaced the PlayStation's ordering table with a more modern triangle function, making the rendering process more efficient.

What was Dominic's approach to memory management in the Wipeout rewrite?

Dominic used a bump allocator, which allocates memory linearly and resets the pointer when a scene or level ends. This approach simplifies memory management by avoiding the need to free individual objects, making it ideal for games with distinct scenes like Wipeout.

What challenges did Dominic face when porting Wipeout to WebAssembly?

The main challenge was ensuring the game could run within the constraints of the web, where infinite loops are not allowed. Dominic had to refactor the code to use callbacks like requestAnimationFrame, allowing the browser to regain control between frames.

What future improvements does Dominic plan for the Wipeout rewrite?

Dominic wants to fix a physics bug that occurs at high frame rates, add graphical effects like lighting on ships, and make the collision response more forgiving. He also dreams of a polished remaster if Sony were to commission it.

What other projects is Dominic working on besides the Wipeout rewrite?

Dominic is currently rewriting his old JavaScript game engine, Impact.js, in C. He has already ported one of his games, Biolab Disaster, to run on the new C engine, which can compile to WebAssembly.

Chapters
Dominic Szablewski, a game developer with a passion for retro gaming, embarked on a project to rewrite the classic PlayStation game Wipeout. He discusses his game development background, his early experiences with Wipeout, and the game's cultural impact.
  • Dominic's early game development experiences
  • Wipeout's cultural significance
  • The game's unique features: fast gameplay, striking art direction, and licensed electronic music

Shownotes Transcript

Translations:
中文

Wipeout is a futuristic racing game that was originally released in 1995 for the PlayStation. The game fused fast gameplay, striking art direction, and licensed electronic music. It was a cultural phenomenon and an early showcase for 3D graphics and console gaming. Dominic Cebluski is an engineer, game developer, and hacker who has released projects such as Voidcall, QuakeVR, and Q1K3, which is a 13-kilobyte version of Quake written in JavaScript.

A version of Wipeout source code was leaked in 2022, and Dominic created a nearly complete rewrite of the game that compiles to Windows, Linux, macOS, and Wasm.

Dominic joins the podcast to talk about the project. Joe Nash is a developer, educator, and award-winning community builder who has worked at companies including GitHub, Twilio, Unity, and PayPal. Joe got his start in software development by creating mods and running servers for Gary's Mod, and game development remains his favorite way to experience and explore new technologies and concepts.

Welcome Dominik, how are you doing? I'm doing great, thanks. Awesome, thank you so much for joining us today. So to kick off, you know, we're here to talk about a rewrit of a classic PlayStation game, but I wanted to know what was your game development journey? How did you get to this point? Oh, it's a pretty long journey. I think the first game I ever wrote was on my parents' 486 in Quick Basic.

But then it got really hard to develop games because developing games for Windows was complicated, setting up compilers and whatever. And I didn't do that for a while. But then later, I completely ignored Flash. But I remember when Steve Jobs announced that the iPhone won't have Flash on it. I thought that maybe there's an opportunity to do it with the things that the browser comes with, like HTML5.

And I developed this HTML5 game engine and was pretty successful with that. And then I did some casual games with the game engine and some original ones. And yeah, I've been always interested in retro gaming too. That's awesome. Yeah. Your game engine Impact, I believe? That is correct. I'm familiar with it. It's good to hear where that came from and the timing about that, because I've always perceived it as a very early HTML5 game engine. And it's great to hear that was literally the stated purpose, which is very cool. Yeah.

So leading into, I guess, what we hear the talk about, where did you get involved in Wipeout? Like was Wipeout a game you played earlier in your life? I've seen you've done a variety of Wipeout related projects leading up to this complete rewrite. Has it always been something you've been interested in? Yeah, kind of. It was one of the most formative games, I would say, when I was growing up.

We had a Super Detender at home and the PlayStation came out and we saw the advertisements for it and it looked so awesome. But it was so expensive. So we sent our father to the local video rental store to pick up a PlayStation for a few days. And he came back with the PlayStation and Wipeout. And maybe another game, I can't remember. But Wipeout was definitely in there and we played it the whole weekend and it was really good. We've never seen anything like that before. Then a few years later, I

I saw in a local shop they had Wipeout for the PC for like 10 euros or something or 10 Deutschmark. So I picked that up and played that a bunch on my PC. But I noticed that it's not that good as the PlayStation original. But nevertheless, I poked around on the CD and I saw that there's PCX graphics and I tried to put my name on a billboard in the game. It never really worked out. I don't know. It was all gobbled in the end.

But yeah, I've been always kind of interested in hacking Wipeout. Awesome. For folks who somehow missed Wipeout, can you tell us a little bit about what the game is and why it captured your attention so much? I think it was a launch title for the original PlayStation in 1995. And it was developed by a British developer and...

And they had a very distinct graphical style. There was a professional graphics designer who did all the logos in the game and all the menu artwork and whatever. But it was really an important game because...

It was like, if you know F-Zero from the Super Nintendo, it was like that, but the grown-up version. And it was like fully 3D. It had polygons and it had like this dance music and like a more serious, maybe not serious, but grown-up vibe to the game. So yeah, I guess I left out the most important thing. It's a racing game, a futuristic racing game, where you fly around in like these hover ships that attach to the track via magnets or something.

Yeah, I mean, you say you missed out the most important bit. You did mention the music. I actually didn't. I was very young when Wipeout came out and I didn't realise until the Noclip documentary just like how much that game was driven, not by wanting to create any particular gameplay, but like the music and how important that was for it. Yeah, also funny you mentioned F-Zero. Again, kind of reflecting on...

F-Zero and Wipeout leading up to this chat today. I was just kind of thinking about how the genre of fast-paced anti-gravity races is very much one that has kind of died off, right? There's no real contemporaries to these games. But there was quite a few titles in this

roster of weirdly specific racing games. There's actually, I'm not sure if I got the name right, I think it's BeamNG. Okay. That is like a modern interpretation of Wipeout. It's on Steam. Interesting. I have to look up the name, but it's pretty good. Awesome. Okay, cool. Good to know. But yeah, there's no like big studios embarking on this again, as it seems. Yeah, absolutely. Cool. So yeah, onto the project. So

You have rewritten Wipeout based on, my understanding, some leaked source code that came out a couple of years ago. Can you fill us in? How did this project start? Well, it started a bit earlier than that, actually. I did a reverse engineering of the data format for Wipeout. When I was young, I tried to put in my name into the graphics and it didn't work out. And later, with a bit more experience, I think in 2016, I tried to figure out all the data formats for Wipeout.

And I built a JavaScript renderer that just loads all the racetracks and ships and just displays it via WebGL in the browser. So I was kind of familiar with the data format already. And I was interested in this Wipeout thing. And then the source code leak happened. I don't think there's any information where exactly it came from, but it just showed up on its website. And it doesn't come with any license. So it's

Kind of a legal gray area, I guess. And while I couldn't really get into it directly, I think it took a year until I found the time and the motivation to really dig into it. Yeah, and I just downloaded the zip file with all the code in it and started digging around. Awesome. Yeah, so the legally gray area, I think, is a really interesting one. Just touch on it briefly. Okay.

You mentioned in your blog post, which by the way, excellent blog post to write up. Everyone, please check out this blog post. Make sure to put it in the show notes. Your blog post about the rewrite that, you know, other people have had to go at this source code and other people have done things with it. And part of the reason that you're going after a rewrite is, you know, part of the fair use play. For folks who are not familiar with the fun world of source code licensing, can you briefly go into that and why, you know, a rewrite in this case is an interesting way to explore the source code?

Well, that's kind of tongue-in-cheek. I guess I'm still in the dark gray area, even with this rewrite.

So yeah, source code is usually, if you write a program, it's usually copyrighted. And if somebody steals your source code, you can sue them for copyright infringement. And then there's licenses you can attach to your source code and say, hey, if you use the source code and modify it, you also have to release a modified source code. That's a GPL license. And then there's more permissive licenses like the MIT license where it's like, oh, you can do whatever you want. And while my argument of the blog post that I lined out is...

Okay, it's based on the original source code, but it's a complete rewrite. None of the lines of code are where they were and everything is different. So I think you can still see the resemblance to the original source code in a lot of places. But yeah, you couldn't make an argument. It's an original work. Yeah. Again, I guess it's kind of gray area. Yeah, I've seen some...

unhinged things done to like make sure it's like a clean room implementation of this kind of thing like someone reading the code describing the algorithm and then giving it to someone who's never seen the code and this kind of thing so it's a really interesting one but it seems like it must be a really you know fun project trying to rebuild this thing in a way that's as you say original and different so with that in mind one of the first questions i guess i wanted to ask you is you know

you know, as we've kind of covered in your introduction, you've done a lot of, I guess I would say like lower level JavaScript programming. You've done WebGL, you've written a framework, but, you know, predominantly from what I saw of your background, you're a web developer, a web engineer. Why did you decide to rewrite it in C instead of, you know, say in, you know, JavaScript or in Impact even? Well, in my day job, I have to write in a lot of languages that are very high level. So JavaScript, I do a lot of PHP, Kotlin and Swift for the iPhone. And

all these very hand-holding languages that are often nice to work with, but they obscure what is really going on. And well, in the recent years, I've just found it interesting to write C in my free time because it's like

You get into this zen state, I guess. So it's very, you have to think about all the details and it's fun to piece it all together. And it's like solving a big puzzle and it gives you all the challenges that you don't have with higher level languages where you just throw together some objects and see what happens. And with C, you really have to be careful what you do. And that's kind of the appeal to me. So I really like writing C even if it's not the economically sensible thing to do.

Yeah, that's awesome. Yeah, I love the approach of, I don't want to say historical, but you know, like earlier programming languages with more of the sharp edges as, you know, a fun alternative to the modern languages you have to use in the workplace. So what is the state of the rewrite? I played it. It was playable. It seems great. How do you look at it?

Well, it's difficult to find more motivation for it now that it's out. You know, once you release something and you get all the praise for it, you kind of stop working on it a lot. It's pretty close to being done. There's still some minor details that are missing. And of course, there's a whole bunch of

improvements that could be done that are like improvements on the original game. Like the original game had a very steep learning curve because the collision response is just so unforgiving. You bump into a wall and you stop dead in the track.

And newer games fix that, the newer games in the Wipeout series. This could be backported to this version too. And then just like graphical effects, like the ships are, for instance, not lit. Like if you go into a dark tunnel, it's not reflected on the ship. And sparks flying when you hit the walls or stuff like that. But yeah, it's playable and it's complete.

There might be a few more physics bugs because I rewrote all the physics code and it's probably not completely frame rate independent in some places. But if you play with 60 FPS, it should be fine. Yeah, so mostly done, I would say. But as always, like the last 10% or 90% of the work. So who knows if Sony would really approach me to ask me to do a full part of this and polish it up. That would probably be a lot more work still.

Perfect. Yeah, I really love that you mentioned the backporting mechanics. We'll come back to that later because I have a whole heap of questions about how you feel about, I guess, like the historical archival purposes of a project like this. But first, I want to get into the rewrite itself and how it came about. And I guess the best place to start is the state of the leaked source code as you found it. I think it's fair to say from your blog post that you weren't super impressed. I believe you used the word abysmal, which I imagine was slightly tongue-in-cheek.

But can you tell us a little bit about the state of the source code as and when this particular version of the game that was released? Yeah, I guess I was pretty harsh in my blog post. You can look at it from two ways. The one way to look at it is just to see the source code and see that's a whole mess. And that, I don't know, the global variables declared in one file are used in another file and it all doesn't make sense. It's all over the place. And then you can look at it from,

the other way and say that, hey, it was a really cool game and a lot of people enjoyed it and it works and it never crashed on the PSX. It's perfectly playable. So it justifies the means maybe to have a working game in the end. So maybe the source code is all bad, but the game is playable. Yeah. Yeah. And I guess how it all came together is if you really dig into the source code and try to figure out what was coming first, you

You can see that maybe the track rendering, the racetrack rendering and the physics for the ships was being implemented first. And then everything else is kind of piled on top of that. And what made the source code really bad in the end is that they also piled on top the PC version. And there's a lot of if devs that like, if this is on PC, do this. If it's on PlayStation, do that. And even for the PlayStation version, they had a lot of if devs for different type of controllers.

And it's all very ad hoc and all piled on top of the previous version. And then, as I mentioned, this game was developed in the UK. So they built the PAL version first, and then they had to do the NTSC version. And because the game wasn't frame rate independent, it had a fixed tick rate.

So it advances the same time step every frame. They had to change it in a bunch of places. And again, they did this with a bunch of if devs. It's like, hey, if this is NTSC, do the time step like this and this much.

And again, the PC version on top, and then there came a GPU accelerated version for the ATI Rage. And it's all cobbled together in the same source code that was leaked. I guess the whole rewrite would have been a lot easier if I just got the clean PAL version PlayStation source. Yeah, but I mean, it must be really interesting to get to see that kind of like layers of archaeology of like the game's history as it's ported and moved from platform and region and that kind of thing.

It was really interesting as well how you described features going missing. I think the track, was it the vertex lighting renderer or something on the track went missing between versions?

Yeah, the original PlayStation version, they had textured tracks that were also vertex-lit. So every vertex of the scene could have a distinct color and they all baked this into the models themselves. So I don't know how they did it. I guess they painted it by hand. I don't think they had like a light calculation. Like, you know, for modern games, you have this light map step or something. I don't think they had that. And all these vertex colors are missing in the

PC DOS version. And actually one of the programmers that was working on this approached me on Twitter and said that, hey, yeah, we tried our best, but it was just too slow. We couldn't do the vertex sliding on top of the textured tracks to make it run fast enough. And then I guess the ATI Rage version that was just like a promo thing, that was really the pinnacle of the garbage. You can see it's just slapped together really quickly and not much care taken.

It's interestingly also by different set of programmers each time. So PC DOS version was handled by other people than the PlayStation version. And the LTIRH version was handled by different people still. And they all had to make sense of what came before. So I guess they had a really tough job too.

Yeah, that ATI Rage one especially really fascinates me. Just the economics of that. Like I remember back in the day when you'd get like a new computer or a new computer component, it would come with like CDs of like free games or whatever. And I imagine that's what this setup was. And so the idea of porting a game to give out under those conditions, like whatever porting house was given that was probably given a miserable budget. So it's kind of understandable. Yeah.

But okay, so going back to some of these layers, one of the things you mentioned just now and also in the blog post was the difference between NTSC and PAL. And this was a thing that I guess like I hadn't thought about for many, many years, basically since. But like growing up, I always had this like vague understanding that these regions existed because sometimes you'd end up with a PlayStation game from the wrong region and whatever. But I've never really looked into the fact there's a technical difference. What actually is the difference between NTSC and PAL and how does that come through in, you know, porting a game?

Well, the main difference for Wipeout was that NTSC was 60 Hz and PAL is 50 Hz. And yeah, that was complicated for all platforms that came before, like Super Nintendo games also had the same problems. And often the developers were kind of lazy and the Super Nintendo version just runs a little bit slower.

And none of us in Europe knew, so nobody cared. But yeah, the main difference comes down to the frame rate. And well, nowadays, everyone has a 60 Hz monitor at least, or even a variable refresh rate.

And the way that games deal with this today is that you have a variable time step. At least that's my understanding. I'm not in the AAA game development sphere. But you just measure how much time has elapsed since the last frame was rendered. So for 60 Hz, that's 16 milliseconds, usually, if you hit your frame rate. And then you just multiply all physics that you do with this time step.

So if you have your speed multiplied with the tick rate, you get a smooth physics integration that is mostly the same on all kinds of different frame rates. But again, back in the day, nobody did that because you were sure, like if you bought a game for the Super Nintendo or PlayStation, you knew you were going to hit 30 FPS or 60 FPS. You knew what your time step was going to be. And it made development a lot easier because you never had to deal with variable time steps and time.

I guess you were also quite limited on these old consoles. So multiplying with a time step for every object that you want to move is kind of prohibitive. I guess it was okay on the PlayStation, but not so much on the consoles that came before. Fascinating. Yeah, I definitely thought about the cost of frame rate independence. That's a good point, actually. Especially the extra mol on my... Yeah, that's got to add up.

Awesome. So speaking of old consoles and, you know, the cost and the hardware. So, you know, any game, even modern ones, are very much, you know, a product of the architecture they were built for. And that's increasingly true, well, more true for console games and especially for Wipeout, which...

You touched on the origin of Wipeout a little bit, but as far as I understood it, not only was it a launch title, but the developer or the publisher was very much involved with making the PlayStation a usable dev platform. So it was all tangled together in a big mess.

Are there any interesting places like in the source code where you really see the PlayStation architecture come through? Like, are there any things that are just like, no one would write this this way for any other console, any other environment. This is purely a PlayStation artifact. Oh, yeah, for sure. There's especially in the rendering code. It is very specific to the PlayStation console environment.

Usually these days when you write a game, you have your game objects and you have your renderer kind of like an abstract thing on the side. So you can maybe switch out your rendering code. Like you want to switch from OpenGL to Vulkan and you just, you know, switch out a module in your code and it mostly works without you having to touch anything.

the source code all over in the game. But again, back then you didn't have this freedom. All this abstraction obviously cost a little bit of compute time and you were writing stuff very close to the metal. You were trying to deal with the things as immediately as you could. So all the rendering code that is in the Wipeout source is very specific to the PlayStation and it's very ad hoc

There's no renderer module that just accepts all the triangles and then tries to figure out how to best submit it to the hardware or something like that. So yeah, that's probably the part that is closest to the PlayStation. But then there's all kinds of different things too, like the controllers, for instance. There's also no abstraction of controller input, like whether you have a PC keyboard attached or a game controller or, I don't know, a racing wheel. All these controllers were also in the source code

like with if statements, like, hey, if this is the PC version and a mouse is attached, then check the mouse coordinates now. It's not like abstracted the way that you have an input module that says, hey, when the mouse moves left, give the input to the game move left. So yeah, very ad hoc. But also I guess it's kind of because the game was so successful and they didn't anticipate they had to port it to so many different platforms that it was just all piled in in the end. Yeah, the renderer sounds...

Nightmarish. That is an especially interesting topic I found. Actually, when I was doing the rewrite, I looked into how the PlayStation produced polygons on the screen. And the most interesting thing to me is that the PlayStation doesn't have a Z-buffer. So if you do 3D rendering and you submit two triangles to the GPU to render and it gets rasterized, the CPU figures out which triangle is in front of the other one with the help of the Z-buffer.

So if you draw a triangle, it gets drawn to the color buffer and you have the Z buffer that just stores the depth value, like the distance to the camera. And if you draw another triangle, it is compared to the stored depth value. If you have a depth value that is closer to the camera than the one you want to write, then you

your object is obscured, at least on this pixel by the previously drawn object. So the GPU doesn't draw it. And you as a programmer, you don't have to care that much about it. You just set up your depth buffer and the GPU does it. But again, the PlayStation didn't have that. And you had to draw all the polygons in the order that they should appear on the screen. So the furthest back triangles need to be drawn first.

And then the closer you get to the camera, it's piled on top. And the development library that came with the PlayStation, they had some kind of cool functions to make that a bit more ergonomic. They had this ordering table where you could set it up and say, I want to have 8,000 different depth values. And for each polygon that you want to draw, you figure out how far it is from the camera. And then you put it into the ordering table at that distance.

And if you do that for all polygons, you have the ordering just right in the end because it is drawn, well, back to front again. So you put everything into the ordering table, just like a big ass array. The implementation details are a bit more interesting than that though. And it gets drawn in the order from back to front.

The implications of that are interesting. Yeah, you have some visual artifacts, for instance. So there's a few cases where you have three triangles on the screen, for instance, and one triangle overlaps the other one, like layered on top, and no triangle is in front of all the other triangles. So each triangle is overlapped by some other triangle. You can't draw that accurately on the PlayStation because you can only draw triangles at one depth value and...

you get around on this problem with modern GPUs with the Z buffer.

So what you would have to do on the PlayStation if you wanted to have this accurately, you would need to subdivide your polygons, basically. So it gets very complicated. And you can see a lot of these issues pop up in the PlayStation games. Like if you look closely, play a PlayStation game, you can see that there are some polygons peeking through where they shouldn't be. But most developers did a very good job of hiding that or the resolution was so bad that you didn't notice or didn't care. Right.

Yeah, I was also immediately just thinking about like, is 8,000 depth values enough? But I guess for most games of the era, it definitely would be. And I guess it's not opinionated on how you define a depth, right? Like that depends on the scale of your game.

MARTIN SPLITT: Yes, exactly. You as the developer, you were responsible for putting it into the right position. So you can say, oh, it's five kilometers away from the camera, so I'll put it at position 6,000 or something. The scale is up to you. MARK MANDEL: Interesting.

Okay, so I guess to start with the question we kind of teased out earlier when you were talking about backporting mechanics, to what extent were you aiming for a, you know, a recreation of this code that's like accurate to how the game worked, like or how the code was versus like the mechanics of the game? Were you just trying to make the game as good as possible? Or was there some effort to preserve the spirit of the source code, if that makes sense?

Well, I started out by just looking at the source code and all I wanted to do is to make it run again, to make it compile and run again on a modern computer. But the more I read into it and the more things I changed, the more I noticed that there's a lot of room for code quality improvements. And for some reason, I really like refactoring code, I guess most programmers do. And one thing led to the other, like, I changed this, now I need to change that.

So I didn't set out to make a full rewrite, but in the end it just happened because I felt it was the best way to approach this, to make the game live on for many more years. Because if you have this garbled original source code, making it run on every platform, on every new platform that comes along, is very time-consuming, very difficult. But if you have a clean slate, kind of

and a clean source code that, in this case, even abstracts the renderer away. So you can plug in another rendering module, make it run on different platforms. That makes it so much easier to keep the game alive too. So yeah, it was all by accident basically.

Awesome. And yeah, you mentioned a new render module. So my next question was going to be, how do you deal with these architectural oddities of the PlayStation? I guess you've changed it to a more modern rendering approach. Is that accurate? Yeah. So the first thing I did was trying to get the thing to compile and run, which was pretty difficult to begin with. And

Well, the first step trying to make it compile was already very challenging because it relies on so many different things that weren't there anymore. For instance, for the ATI Rage version, all kinds of windows headers that I didn't have or GPUs that don't exist anymore. And for the PlayStation version, same thing. I don't have a PlayStation to compile this for and the PlayStation libraries are missing.

So I just ripped out everything that wasn't really essential to start the game. So commenting out all the places where polygons are rendered, commenting out all the places where controller input is checked, commenting out places where something PlayStation specific happened. And then finally I got it to compile. And then I started to slowly adding things back in again. Again, the PlayStation version was using this ordering table and transforming polygons on the

on a coprocessor, but the DOS version was doing the transformation on the CPU and they had all the routines to do that there. But they were still using this ordering table because it was so ingrained into the source code.

And I started using this ordering table too. I just, you know, all the transformation of the polygons that runs on every CPU, you can run it on a modern computer. And just then the last step, like when these polygons are handed over to the GPU, I exchanged that, like how it goes through the ordering table and gets it to the display. Yeah, the first thing I had was this flat shaded version of Wipeout where it just had something on the screen that runs Wipeout.

And from there on, I started to clean things up more, like getting rid of this ordering table and having a proper triangle function and using that instead of sticking stuff into the ordering table all over the place. Yeah, so...

Step by step, very, very slow progress at times, very tedious because also you, you tried to get rid of something that was, that was in there and rewrite it. And then you were working for five, six hours on it and you could not compile in between to see if it works because you were like changing so much to facilitate that.

So yeah, often quite adventurous, but a lot of fun too. A question I realized I didn't ask that I should have done is, do you have an idea? Sorry, this is like a hard numbers question on top of your head. Like how big was the original source leak in terms of lines of code? And how big was it ended up being in the rewrite? I think I actually have the statistics in my blog post. Oh, really? Yeah.

But the way that you count it is kind of complicated by the fact that there were three versions of the game in the source code leak, but none of these were working independently. Like if you wanted to compile the PC DOS version, it pulled in some source code from the PlayStation version too. So I don't know how to calculate that accurately. Again, it would have been nice to get the source code for the original PlayStation version because then you would have the more accurate number on that.

Okay, I found it. So 40,000 lines of code in the leak versus about 8,000 is what you ended up with. Yeah. Again, yeah, a lot of things were just, you saw the same if statements all over the place. Like, hey, if it is this controller, do that. If it is this other controller, do that. And if you just abstract that away into like an input module, you get rid of a lot of repetition and a lot of source code, a lot of source lines. Awesome.

Awesome. So you mentioned there that, you know, you abstracted some things away so you could use, you know, different renderers, different backends, etc. They've got the game running on both STL2 and Sokol, is that correct? That is correct, yes. I started out with STL2. I'm doing this on Linux and I just had OpenGL here and so I tried to get that running first. And while

Well, there's two things you can swap out. The rewritten source code is built in a way that you can swap out the, what I call platform, and that is SDL or the so-called app. And then you can swap out the renderer. So currently there's the official OpenGL version and I have a wireframe software rendered version. And other people have written odds to metal for macOS and...

Trying to remember if I saw something else. Maybe someone ported it to some newer console again. I'm not sure. So yeah, I started out with the STL platform and because I knew that I wanted to have the possibility to have different platforms, adding then the so-called backend was quite straightforward. There's only very few functions that the platform needs to implement, like setting up the window, sound output and stuff like that.

And SoCal is actually very cool. Like libstl is a big library and you get the header files so that you can compile your code. But then you also have this library that you either need to also link to your binary or just dynamically link. And I think it's like three megabytes or something. And SoCal, on the other hand, is you are expected to include the whole source code.

And it comes all in one file and you just include it in your C source and it just works. And I was actually very surprised when I got this working on my desktop and I could open a window with Sokol and play the game and input works and whatever.

I just had to switch out the compiler from the usual GCC to EMScripten and it compiled the web version and it just works. I could play the game and sound output worked, graphics via WebGL worked. It was kind of amazing. I expected a lot more struggling to make it work on the web. Yeah.

Yeah, I hadn't heard of it before your project. But yeah, that's pretty nifty. And it does lead me into my next question was, you know, you're targeting Wasm, you're targeting web platform. I guess you've kind of just answered it, which is you didn't really have to do anything special because Circle handed it for you. But was there anything during the rewrite where you had to keep it in mind that you were targeting Wasm? Well, other than that, I wanted to target different platforms. Not really, because, you know, I was using OpenGL anyway, and I knew WebGL was pretty close to that.

You have this GL ES2. And I didn't need any fancy shader code. Like, I don't have any shadow calculations or whatever. It's just textured triangles with a color as basic as it gets. And WebGL can do that just fine. So in that regard, I didn't

didn't need to think about any changes. In the end, I had to do a little bit of work for the WASM version to make it work on mobile, especially, you know, I needed to have some buttons on the screen that are then forwarded to the C code. And that was a little bit of work. And it's not really...

not really fun to play because these on-screen buttons are not very responsive and positioned wrong. And it's more like a proof of concept. It works on mobile and it renders just fine on your iPhone or something. Yeah, I am surprised that works on... I can't imagine playing Wipeout on an iPhone. With buttons in the way, I always already feel like it's just like too fast-paced for that small screen. So I guess to rewind a little bit and go back to rewriting stuff, there was a couple of interesting parts in your...

blog post where you mentioned like not even necessarily looking at the original source code because it was just like too spaghetti-ish and instead just looking at like videos of the game being played or playing games on the emulator. Can you talk through some of those areas and like why you took that approach to it? Well, one of the areas was the sound code. Again, very specific to what was happening on the PlayStation and

This was actually fairly abstracted away. So in the game, there were calls to just play a sound at a certain position. And I knew what the game wanted to do.

And I just thought that, okay, instead of digging through all this sound code that is there, I just re-implemented because I know what they want to achieve. There's music playing, there's sounds playing at different positions, and I know where they get called. And it was a pretty good decision, I would say, because again,

Again, the original code was so specific to the PlayStation that it would have taken a lot of time to figure everything out. And just rewriting it was the faster way. There's one thing missing, though. The original PlayStation had this hall effect. Like if you go into a tunnel, you could hear like a reverb of your engine sound and also a reverb of the music that is playing. And that is still missing from the rewrite.

Interesting. Reverb of the music that's playing is also an interesting one because that implies it's coming from the ship and isn't just background music, which I'd never noticed before. One thing you said in the podcast really interested me because I hadn't heard the term before. So at one point you described that the original code followed a you call the platform approach and you wanted a platform calls you approach. What do you mean by that?

So typically the way you wrote games is like you start your program, you load your graphics and your sound files and everything that you need to run the game. And then you go into an infinite loop that just runs forever. And in this infinite loop, you check if any buttons are pressed, you advance your physics calculations. So advance the world state, and then you put everything onto the screen. Then it goes into the next iteration.

So you call the platform, you call everything that you need to do by yourself. So you wait in your own code for the next, until the renderer is done and you submit everything to the renderer. And you can't do that on the web and in WebAssembly because you would basically crash the whole page or stall the page. You cannot go into an infinite loop. You have to give control back to the browser.

So, like if you have in JavaScript, if you just write a loop in JavaScript that runs forever, the browser after 15 seconds will say, hey, this page is not responding anymore. And you can't interact with this page in the meantime. So all this, because JavaScript is single threaded, there's nothing running in the background if you don't use web work or something like that.

And if you want to render a game and put something on through the screen, you do your physics calculations, pull for input, and put it on the screen. And then you give control back to the browser and wait until your code is getting called again. So what you do is you just set up an interval or a request animation frame these days, where you just say, I want to get this callback called every 16 milliseconds.

In these callbacks, you do all the things that you need to do, and then you return. And that's the only way you can do it on the web. And interestingly, the original Wipeout code didn't have just one infinite loop. Like even if you implement the game cleanly, you would have just one loop that handles all kinds of different scenes.

So you have your infinite loop that pulls for input. And then if you are in the menu scene, you show the menu and handle the menu buttons and whatever. And if you're in the game, you advance the physics. And you have this very outermost infinite loop.

And Wipeout does this. It has this infinite loop on the title screen. So it just shows an image and says, "Press Start." And there's an infinite loop that just blinks the "Press Start" button. And as soon as you press start, it jumps to another part of the code where there is another infinite loop. Oh, I see. And you have this infinite loop for the menu. And then if you go into the game, you had another infinite loop in the race functions.

So lots of different infinite loops that you have to untangle. And yeah, it was quite some work to figure all this out and where you switch between those loops and how you maintain those.

all the state and all the things that were loaded. Like, which kind of graphics do you still need? Which kind of graphics can you throw away? Because they are from a different racetrack or something. There was quite a bit of work. Yeah, that sounds nightmarish. But yes, you've just reminded me, speaking of which graphics you retain, you had an interesting approach to the memory management in the rewrite, right? Which is you did away with allocating memory and just

said, "I will have this much memory and that's all I need forever." Can you talk a little bit about that? Yeah, it's actually a pretty standard approach in a lot of game development that you have a bump allocator. So that's a big area of memory that you allocate first.

And then you say, I start at the index zero. And if I want to have, I don't know, 1000 bytes of memory, you just advance this index to 1000 and give back the memory address that was at zero. And then next time you want like 20 bytes, you advance the index by 20 and just give back what was at the previous position. And so it's just like a linear memory that just grows and grows and grows.

and everything grows on top of the previously allocated thing. And then if you don't need your memory anymore, you just reset your index to zero and you don't have to free anything. You just know that all the memory that I allocated here is free now. And a lot of games these days do this for, like they have this bump allocator

a frame. So at the start of the frame, they start at zero and some things in the game need to allocate some memory to do some calculations or whatever. And the allocator grows and grows and grows. And at the end of the frame, it's reset to zero again. So you as the developer, you as the game developer, you never have to care about

memory allocations. As long as your buffer in total is big enough to handle one frame, you don't have to free anything ever again because it's automatically freed at the end of the frame. And you can use that concept

you can further that by just saying, "Hey, I don't only have one of these bump allocators, but I have multiple ones." So one that is like per frame and another one that I do, I don't know, per level. So each time a level gets loaded, it's reset. And yeah, the way I did this in Wipeout is there's actually just one bump allocator, but it remembers

different levels. So first when the game starts up it's at zero and then I load some graphics that the whole game needs like for instance the graphics for the font and the ships are needed in all races and the textures for the ships and these are put into the bump allocator and then when you start a race the position of the bump allocator is recorded and then I load the race track

into this bump allocator. And when the race finishes, it's just reset to this position again. And the racetrack is basically thrown away and makes room for the next racetrack to load. So that's a very, very simple approach to memory management and it works

I have to say it worked really well for this game because you have these very distinct scenes that all have their own graphics and own models. And yeah, you have some models that you just load before you load the first scene, like the ships and whatever, and they just persist all the time. So yeah, you never have to free anything and you know that you cannot leak memory because it

it's reset to the previous level again i think you answered the main question i had so i wasn't familiar with that concept so it's really interesting thank you for diving into it but i guess the main thing you have to do here is like logically group what you're loading because you couldn't for example like free something in the middle of a block right like you're freeing up you're just resetting the point about certain things you've got no scope to you know remove things within a area right okay

Yes, exactly. So yeah, you cannot free something from the middle and make room again. Everything that is in there is in there until you reset the pointer, yes. Which then is ideal for, as you said, something with very discreet, obvious scenes, like a racetrack-based game. Gets actually a tiny bit more complicated in Wipeout because I needed some of this memory that I can free out of order again. So for instance, when you load a racetrack,

from the disk, from a file. The whole file is loaded first and then I go through this file and look for all the data that I need for all the vertices and whatever. And I put them into another structure that is more efficient for rendering.

And this is the final data that I use in the game is put into the bump allocator. But the file that I load, I can free again later. So I needed to have what I call the temporary allocator for these very short-lived objects that you have to explicitly free again. And yeah, this is mostly used for loading files and transforming them in some way. And one thing about that, I think

I think the whole game allocates 16 megabytes at the start of the game for this bump allocator. And the bump allocator grows from zero to 16 megabytes. And the temp allocator actually lives in the same 16 megabyte space, but it grows from the end.

to cross downwards. So if those two allocators ever meet you out of memory. - Flame of fire. But then I guess, as you said, when you're building these kinds of games or building for the constraints of those consoles, you often knew exactly what you needed at any point, right? Like there's- - Yeah. And also I can be sure that everything fits into memory because I tested it. Like there's no edge case where something is loaded that I didn't foresee to be loaded. Like these are very distinct scenes. And as long as all the scenes, all the racetracks load just fine,

I know the memory level will be reset to a known value. And I, if the game fits, it fits. It's one of those things I guess I always struggle with as like high level programming is like, you've always got that temptation to make the thing work for every case, right. And to make it as like maximally abstract and maximally generic and maximally fault tolerant. But like, sometimes you actually do just know exactly how much memory you're putting in the data structure and you can just rely on that. And it's so, it makes me itchy, like accepting that, but it is, it works and it makes the game work and that's fine. Yeah.

Yeah, realistically, yeah. If you develop for the PlayStation, you know you only have, I think it was four megabytes or maybe even two megabytes of RAM. You know the room that you have to work with. So yeah, there's no advantage to using very dynamic memory allocation and freeing objects all over the place. Perfect.

So I guess moving on to future looking questions. So you mentioned, you know, a lot of the motivation has gone out now that it's released. But is there anything you still want to tackle for the rewrite? Is there anything you hope to see happen with it? Well, I still want to investigate this. There's probably a physics bug you can crash into the racetrack when your frame rate is too high. And I figured that out by...

I implemented this very crude version of motion blur. Because the game runs with 5000 frames per second on my computer anyway, I only have a 60 hertz monitor. I thought, okay, let's just, you know, I have 16 milliseconds between each frame. Why not divide 16 by 8 and just advance the game

two milliseconds at a time and render a frame. And I take eight of these frames together and blend between them. And that is the final output frame that is sent to the display. So this is how the motion blur is implemented. It's like the real version of motion blur. It's very computationally expensive, but with this game it's trivial to do because it runs so fast.

And I basically had eight times the number of frames that are being processed. And the physics step was getting very, very tiny, like just these two milliseconds. And there is some back in there somewhere that makes you crash into the ground. And I want to fix that so that it's truly frame rate independent.

And yeah, if I find the motivation, I want to do some of the graphical things like lighting on the ship when you go into a tunnel that gets a bit darker and stuff like that. And maybe also the more forgiving collision. But yeah, I lined this out in the blog post too. My dream would be to...

be paid to make a very polished version of that. It would be very cool if Sony says, like, hey, now it's the 38th anniversary of Wipeout. It will be actually next year, I guess. It will be next year, yeah. And we are in remaster season. We've done Tomb Raider. It's time for Wipeout, right? So, yeah, good timing then. Sony, if you're listening to this, you know where Dominic is. Yeah.

Yeah, that makes total sense. I hope that happens. And yeah, I hope the big corporation is nice about it. That would be lovely as well. So outside of Wipeout, do you have any upcoming game projects you're excited about? Any other rewrites of random source code? I saw you're making a C version of Impact as well. Is that just dabbling?

That is true. Yeah, I got it into this rewriting, I guess. So Impact.js was one of the very first JavaScript game engines, maybe the first one. I'm not exactly sure. And that's from 2010, I think.

And yeah, I got a lot of experience writing C by doing the swipe out stuff and a few projects before. And I thought that, hey, it might be fun to revisit the game engine and see if I could reimplement this elegantly in C code again. And I've gotten pretty far now. So the first game that I developed with my own game engine, Biolab Disaster, it's still playable on the web.

It's now rewritten in C and you can compile it for your desktop and also again, compile it with WebAssembly and play it on the web again. Amazing. I'll have to go full circle and rewrite your web game engine to C to compile to Wasm. That's incredible. Yeah. So the plan for that is to just release it as open source, maybe write a bit of documentation for it and see what people are doing with it. Yeah. Just a side project. Nice.

Nice. Well, it sounds like a very cool side project. It's fun to catch the sea bug. I'm glad that this is an outcome of the Wipeout project is going back and writing more sea. That's fun. Perfect. Well, in that case, thank you so much for chatting to us about Wipeout. You are Phobos Labs. Everyone on the internet, people want to read about your work, the upcoming engine, the Wipeout rewrite is on GitHub as well. Underneath that handle, we'll include it in the show notes. Anywhere else where people can find you that I've missed. Phobos Labs everywhere.

Well, GitHub, the blog and Twitter mainly. Perfect. Awesome. Well, Dominic, thank you so much for joining us today. Thanks for having me.