Great article. I particularly enjoyed the approach to creating gibs.
Although it was a tech demo, I created something like this around the mid 90s. One thing I did that I don't see mentioned in this article was I used 8x8 (or 16x16) light maps on the textures, which allowed me to easily have things like flickering torches and rockets that lit up the hallways as they shot down them. Lightmaps can also be used to "bake in" lighting if desired.
Since the light map is "only" 8x8 you can afford to do some math on each luxel (each unit in the light map) to calculate distance and line of sight to light sources to determine a brightness value. When rendering the texture, the luxel was used with a lookup table to determine the actual color of the pixel being drawn. The light maps were updated 15 times a second if I recall correctly to help performance. Thanks to DJGPP, I was using inline assembly for the rendering. Since floating point math was slow at the time I used fixed point math which optimized well. The rendering was surprisingly performant on computers of the day.
pragma_x 24 hours ago [-]
> I used fixed point math which optimized well.
I feel like the idea of fixed-point is under-utilized and very under appreciated. There are loads of applications where this is a better choice, let alone more performant.
dhosek 23 hours ago [-]
This was the choice that Knuth made in TeX and Metafont although it’s also at least in part because floating point implementations in the late 70s/early 80s were so inconsistent from one platform to the next that using native floating point couldn’t satisfy his requirement of identical output on all platforms (likewise, the variations of Pascal implementations meant that he also used a highly restricted subset of Pascal features and no dynamic memory allocation).
rob74 1 days ago [-]
This is taking a lot of inspiration from Doom, but the actual raycasting engine is more like Doom's predecessors, the most well-known of which is probably Wolfenstein 3D: perpendicular walls, constant floor and ceiling height. Wolf3D didn't have textured floors and ceilings because of performance reasons, but several other similar games had them. Doom and IIRC Duke Nukem as well used a BSP engine which was much more flexible (walls could intersect at any angle, variable floor and ceiling heights), although the levels were still "flat" (you couldn't have several "stories" inside a level, e.g. you couldn't design a bridge that you could walk over and under).
badsectoracula 1 days ago [-]
> Duke Nukem as well used a BSP engine
The Build engine didn't use BSP, it treated connections between sectors as portals and rasterized the walls as (90 degree rotated) trapezoids while performing clipping against those portals. This allowed it to have dynamic wall geometry (e.g. moving trains, rotating light fixtures, etc) as well as "room-over-room" setups as long as you couldn't see both rooms at the same time (in both Blood and Shadow Warrior they found a workaround for it allowing to create more "3D" spaces by making identically shaped sectors with the floor of one sector acting as a portal to the ceiling of the other sector - supposedly this wasn't "natively" supported by the engine, but it was flexible enough for the game studios who used it -without even having access to the source- to do it themselves).
The first level of Duke Nukem 3D does use a few Build tricks - e.g. another one is that sprites can be "axis aligned" instead of following the camera and they can also have collision - this can be used to create rudimentary 3D geometry by treating each sprite as an axis aligned quad and in the first level it is used to make a bridge between two buildings (right before the level exit button).
jamesfinlayson 17 hours ago [-]
I saw recently on the website of the guy who built the Build engine that licensees got some .c files and some .o files (with the rough breakdown being game code in .c files and engine code in .o files) but I guess if you knew enough you could hack around.
torginus 10 hours ago [-]
Though it must be said that Duke's flexibility came with a tradeoff - while BSPs will find a leaf node in log(n) time, no such guarantee exists for Duke and its up to the mappers to optimize the maps so that the renderer doesn't need to traverse a large amount of sectors.
kridsdale1 1 days ago [-]
I always loved that the bridge you mentioned could take damage and fall down, screwing you over in the very first level, unless you knew where the Jetpack was stashed.
ant6n 20 hours ago [-]
The funny thing is that looking backwards, I would never use a grid of squares for a raycaster like wolfenstein3d did.
If I were to do a raycaster today, I would use convex sectors with portals, basically like duke nukem, but constant wall heights. You can do drawing very simply by just doing a linear pass across the sector, recursively stepping into other sectors.
Then you can at least do arbitrary level geometries.
badsectoracula 18 hours ago [-]
Yeah, that is basically what i did around 2009 when i was making a 3D engine in Haxe for Flash, RayFaster 2 (it was the successor to another Flash game engine, RayFaster, which did Wolf3D-like raycasting and i used to make a simple FPS[0] though with Flash's input limitations i couldn't do mouselook and didn't feel that great).
The engine used Build/Doom-like maps and would simply raycast against the camera's current sector (sectors could be any shape not just convex) and used connections between sectors as portals to recursively follow the (2D) map until it hit a solid wall - so basically Build's portal rendering approach except using raycasting instead of trapezoid rasterization. It could also do sprite rendering (you could have both sprites facing the camera and "aligned" sprites that could be used for decals) and even had some simple 3D model rendering (the triangles were sorted and clipped against the portal during rasterization). Unfortunately Flash isn't available in browsers anymore and Ruffle isn't compatible with it (it can run the engine -much slower than real Flash- but the palette is all wrong), so i took some shots using the standalone Flash "projector"[1][2][3][4]. Also making maps for it was certainly much more laborsome than making maps for a Wolf3D-like game and that combined with me losing interest in making Flash games meant i never made a game with it.
A grid of squares makes sense for the target hardware at the time though (286 or better CPU)
ant6n 11 hours ago [-]
It really doesn't. I would argue that convex sectors with portals could be quicker than casting rays across a grid for every pixel column, except for some degenerate cases. This is because for any pixel column in-between the boundaries of wall segments, there's virtually no work to be done (O(1)), compared to the work of casting a ray along the grid O(n).
Btw, 286 played wolfenstein rather poorly. The 386 is rather more appropriate.
Wolfenstein was built in a couple of months by a then 21-year-old Carmack. He didn't focus on optimizing levels until Doom.
bananaboy 5 hours ago [-]
Yes, I played it at the time on both a 286 and a 386. You might be right, although you're describing an algorithm more like what Duke3d used rather than raycasting in that case. I was talking purely about raycasting. So it sounds like a misunderstanding on my part.
It's true that Carmack has said several times, including in the readme to the source release of Wolf3d [0], that a BSP-based renderer might be faster than raycasting. He used a BSP tree based renderer for the SNES port of Wolf3d because the CPU was even slower, so I suppose that answers it! There's also a note in the GEBB page 164 from Carmack where he says it was slower than "looping through a few long wall segments". [1]
Early alpha versions of DOOM used a sector-based rendering technique, maybe like what you're describing, which ultimately was too slow [2]][3]. Then Carmack switched to BSP trees after doing the Wolf3d SNES port.
I think it would be pretty interesting to implement the same game with both a raycasting approach and a BSP or Build-style portal/sector approach and compare performance on a 386. DOOM ran terribly on a 386 but it did a lot more than Wolf3d, so it's not a great comparison. Catacomb 3D didn't use raycasting (it used a wall span rendering techniqe) and ran better than Wolf3d on similar hardware, but it had a bunch of glitches. But Carmack says they were due to lack of experience rather than the technique itself.
Anyway thanks for challenging my assumptions. This'll go on my todo list!
Huh, I always thought RoTT was the first Build engine game.
Grumbledour 1 days ago [-]
Later on, in Shadow Warrior, you could even do that, i think they used portals to implement it and i remeber it was a pain to set up in the editor.
kridsdale1 1 days ago [-]
That did give us our first software rendered transparent water rooms though (Quake had the water opaque unless you had 3DFX card IIRC)
mrob 1 days ago [-]
GLQuake introduced the r_wateralpha setting, which allowed transparent water, but the maps were still compiled with visibility calculations that assumed the water surfaces were opaque. You got visual artifacts unless you enabled r_novis to ignore the pre-calculated visibility calculations. Modern computers can handle it, but this was a heavy performance cost at the time.
To work around this, people used an unofficial tool to patch the maps to support transparent water:
Don't forget the optional voxel models! They did some really cool stuff with Build. I loved some of the creative uses of things like controllable vehicles (sometimes with guns!).
classichasclass 1 days ago [-]
Yes, essentially with a second rendering pass. Not cheap to implement which is why the game used it relatively sparingly.
akoboldfrying 16 hours ago [-]
No man is island, except Lo Wang.
torginus 9 hours ago [-]
I think the argument could be made both that both engines are raycasters, though they don't cast rays over pixels, but horizontal 2D spans (where each ray is going to end in the same sector).
With the data structure being more efficient, and doing less overall work, I think this part of the Doom/Duke engine might even be faster than than Wolf3D
scrumper 1 days ago [-]
I thought at first it was just a skinned Wolfenstein 3D. Which is grossly unfair. A lot of work here.
torginus 1 days ago [-]
With regard to floors, afaik even DOOM didn't do them correctly. With vertical walls, the perspective divide needs to be done only once per column of pixels for a given wall segment.
For floors, unfortunately there's no such luxury, and if I remember correctly DOOM subdivided floors into patches, and only did proper perspective at the corners, and interpolated inbetween.
Jare 24 hours ago [-]
For floors the perspective divide is once per row, just like for walls it's once per column.
The BSP may have led to some floor subdivisions, especially as it needs convex sectors. I don't remember if the engine would coalesce adjacent floor spans into a single one, but I hope it did.
torginus 23 hours ago [-]
That would only be true if a row (by which I mean a scanline) would be equidistant in view-space depth across its whole length, which is not quite true. While a column of pixels for a wall is (as long as you dont tilt the camera).
And it looks to me like we are mapping each row with a constant y, calculating the "distance" (thus scale factor) only once using just the vertical slope for the row.
torginus 10 hours ago [-]
Yeah sorry, you are right - I got it mixed up.
mkl 1 days ago [-]
Graphics programming in the early to mid 1990s was pretty fun: write pixel data into the memory-mapped video RAM and it appears on the screen! A pointer to 0xA0000 was all you needed - no API or anything. The reason for the non-square-pixel 320×200 VGA mode they mention was that the video buffer took 64000 bytes, which fit into a 16-bit segment, making addressing it easy in 16-bit code/CPUs.
HerbManic 19 hours ago [-]
I always found it really funny that PC's had these absolute monsters of CPU's relative to the consoles of the time but because of the graphics setup they struggled to do smooth scrolling like Mario on the NES in 1985. But that weakness meant you could essentially do a lot more work per pixel on screen and thus allowed these ray casting/BSP tree systems.
So while it didn't have custom processors for sprites and background layers it meant there wasn't a rigid fixed function nature to what the PC could do.
By the mid-late 90's with dedicated 3D processor this wasn't an issue any more but there was a brief time in the early 90's where there was this wonderland of unique visual rendering.
badsectoracula 1 days ago [-]
> A pointer to 0xA0000 was all you needed
Though your extender could make things a little more annoying on that front :-P
(DJGPP and Free Pascal -which use the same "go32" extender by DJ Delorie- do not do a full linear mapping so you need to do a bit more juggling to get stuff on screen there)
1313ed01 4 hours ago [-]
There is 16-bit DOS support in Free Pascal these days (yes, added long after 32-bit DOS support). That makes it easier to get a pointer to video memory. Makes other things less easy.
Also some (more) free (open source) 16-bit C-compilers now, like the ia16 gcc port and Microsoft's C compiler included in the MS-DOS repo on GitHub.
Not that 32-bit extenders do not come with some advantages, but I enjoy the simplicity of 16-bit.
russdill 1 days ago [-]
Until VGA came along....the story was much more complex.
mkl 21 hours ago [-]
No, I'm talking about VGA. Super VGA is where it got more complicated, with its many variations, higher resolutions, and higher bit depths.
pan69 20 hours ago [-]
I think GP is referring to EGA which also used address 0xA0000 but you had to program it in it a planer mode of 16 colors out of a palette of 64. VGA provided backward compatibility with this but introduced the 256 color modes with mode 13h being the linear addressable 320x200 res mode, however this mode sacrificed 3/4 of the video memory. This mode was also referred to as "chained" mode as it chained all 4 bitplanes together for convenient linear addressing. There was also unchained mode, sometimes referred to as mode-x which allowed you to access all 256kb of video memory, resize the virtual screen, page flipping, etc. at the cost of compute overhead. Lots of tradeoffs to be made in those days. Some amazing looking 16 colors VGA games were produced in the early 90s, one that comes to mind is Gods by Bitmap Brothers.
russdill 17 hours ago [-]
Yes, and if you want to go program for some other platform? The limitations and complications are completely different.
corysama 1 days ago [-]
If you want to play with software rendering, here's probably the shortest code that will get an ARGB8888 2D array from main memory to the screen efficiently for all platforms using SDL2 in C https://gist.github.com/CoryBloyd/6725bb78323bb1157ff8d4175d... you'll need to do the translation from a 320x200x8-bit palletized framebuffer to ARGB yourself ;)
At least with SDL3, you don't even need the renderer or the texture anymore. SDL_GetWindowSurface to get the surface and SDL_UpdateWindowSurface to present. That's the more software-graphics you can get from my understanding of the library. SDL still does the double-buffering for you.
TazeTSchnitzel 5 hours ago [-]
SDL has always made it easy to directly present a software buffer of pixels to the screen. I'm not sure why someone would want to use the renderer/texture thing for this use case.
bellowsgulch 22 hours ago [-]
Thank you for sharing this. There's a handful of very popular Quake forks already, but Planimeter publishes a Quake-VS2026 fork that doesn't introduce changes. The team is working on x64 builds, which requires replacing the old SciTech Mult-platform Graphics Library (x86 only) with SDL3 (or port scitech-mgl to x64, which I don't think will happen) and the last I understood, the software renderer may be dropped.
But maybe a software renderer and SDL_Texture could preserve it?
pan69 21 hours ago [-]
It's certainly the most rudimentary. Small optimisation on the inner-loop would be to pre-calculate the scanline offset before going into the pixel loop:
int s = y*screenRect.w;
for (int x = 0; x < screenRect.w; x++) {
pixels[s + x] = argb(255, frame>>3, y+frame, x+frame);
}
kmill 19 hours ago [-]
I'd be surprised if the compiler didn't make that optimisation on its own.
canyp 15 hours ago [-]
Possibly, but always check the assembly.
The even faster version, opts aside, would be to initialize the pointer at y*screenRect.w and ++ at every loop to avoid the addressing arithmetic.
kmill 11 hours ago [-]
Certainly check the assembly, but loop invariant code motion and strength reduction are basic optimizations. C compilers tend to be good at optimizing indexing patterns even at -O1.
Take a look, GCC and Clang go further than these suggestions by adding screenRect.w to the pointer each iteration to avoid the multiplication: https://godbolt.org/z/YfroqK7T6
Writing anything but pixels[y*screenRect.w + x] in an attempt to be faster, without checking the assembly first, is obfuscation.
(For what it's worth, you can beat the compiler by using *pixels++. I didn't profile the code to check it actually was faster in practice however.)
rob74 1 days ago [-]
I just noticed that this might be one of the rare shooters with a female protagonist: the cat has a calico pattern, and those are almost always female (https://en.wikipedia.org/wiki/Calico_cat).
embedding-shape 1 days ago [-]
> rare shooters with a female protagonist
It's not that rare, is it? Off-hand, and very mainstream; Perfect Dark, Mirrors Edge, Dishonored (don't remember if it's the first or second one), Metroid and more are all kind of "shooters" with female protagonist, although maybe Mirror's Edge is more just "first-person" than "shooter" to be 100% accurate.
Not to mention the large selection of "RPG + FPS" where you can be either man or woman.
---------
Seems the author also realize the thing with the pattern and likely gender of the cat:
> After all, I do need to give the protagonist his fair share. [image] (Yes, I know it's a female, but call it convention rooted in dialect.)
EvanAnderson 1 days ago [-]
Not a "shooter", but the "No One Lives Forever" franchise is another example of a female protagonist in a first person game.
> The character of Prisoner 849 is commonly speculated to be Gina, as her model (Female 1) and skin are the first character to appear in alphabetical order; this is even reinforced by UnCreature giving the female player a bio while the male player bio just reads "See Female Player". However, the character of Prisoner 849 is completely up to the player's choice, hence the use of neutral nouns in this article.
KerrAvon 1 days ago [-]
If Portal counts, so does Control
egypturnash 1 days ago [-]
Control's not first-person. You are looking at Jesse's back for pretty much every moment of gameplay.
They're definitely rare. Mirror's Edge is almost 20 years old. Reaching back that far for an example just reinforces how rare it is.
If you tally all the FPS releases in a given year, a supermajority are going to have male protagonists.
amiga386 1 days ago [-]
???
Mirror's Edge has a female protagonist, but it's not an FPS (First Person Shooter). It's a parkour simulator which technically lets you shoot a gun in limited sections of the game, but the protagonist is a pacifist and you get a bonus for decommisioning guns rather than firing them.
So it looks like the two categorisations, for the most part, don't intersect.
Notable counterexamples would include Rise of the Triad, Ion Fury, No One Lives Forever, Wolfenstein: Youngblood and Far Cry 6, but definitely rare. You'd be clutching at straws to describe Portal or Alien: Isolation as FPS (they're a puzzle game and survival horror game respectively), likewise the Resident Evil / Clock Tower / Fatal Frame / etc. games with the novelty option of switching to first-person view, they're naturally third-person perspective. Left 4 Dead has one female character out of four you can play. You might count that one DLC for Bioshock: Infinite where Elizabeth gets a shot (https://www.youtube.com/watch?v=1E1lh-pb6Is). You might count the few FPS RPGs that there are with customisable characters (so yes Fallout, but not Mass Effect as it's third-person). But female protagonists are massively more prevalent in survival horror, metroidvania, third-person shooters (Tomb Raider, Monster Hunter, Horizon Zero Dawn, etc) and other genres besides FPS.
shakow 18 hours ago [-]
> They're definitely rare. Mirror's Edge is almost 20 years old
You probably didn't play many FPS recently: from the top of my mind, CS2, Battlefield {1, V, 6}, CoD {BO3, Vanguard, MWIII}, Control, the Borderlands, Far Cry {5, 6}, CP2077, Fallout {3, NV, 4}, Destiny, Prey, Valorant, Rainbow 6, Apex, Overwatch, all have female player characters.
And if CS2/CoD/BF/Valorant/Destiny/Apex have female players, that's more or less 90% of the current market.
I took a glance at the the most played FPS list from Steam[0], but I was too lazy to scroll far enough to find one without a playable female character.
> Reaching back that far for an example just reinforces how rare it is.
Choosing one specific example when I also made more recent ones, isn't such a big dunk you think it is.
> If you tally all the FPS releases in a given year, a supermajority are going to have male protagonists.
Sure, I agree, I'm not saying it's more popular, just that I don't think it's that rare, but I guess ultimately I'm a bit nitpicky (sorry) and we're just disagreeing with the specific definition of "rare".
dabluecaboose 1 days ago [-]
> one of the rare shooters with a female protagonist
No, this isn't a Perfect Dark game
kridsdale1 1 days ago [-]
Well done.
badsectoracula 1 days ago [-]
A lot of boomer shooters nowadays have a female protagonist, e.g. Selaco[0], Supplice[1], The Citadel[2] and its sequel[3], Zortch[4] (and its upcoming sequel[5]), Nighmare Reaper[6], COVEN[7], Viscerafest[8], Hedon[9], etc. If anything i'd say that nowadays there are way more boomer shooters with female protagonists than not :-P (combining the tags "boomer shooter" with "female protagonist" on Steam search gives 143 results, though that includes games where you can either choose your character's gender or you play as a woman for a part of the game even if you play as a man for most of it).
So a bit less than 1/10 of the games tagged with "boomer shooter". With your caveats above about being able to choose a gender, or a single brief segment where you're a lady in a game where you're mostly a dude. Is that a lot? I dunno, doesn't feel like a lot to me. Probably feels like a lot to the people who inevitably show up in the Steam discussions of any successful game that makes you be a lady for most of its length and complain about it being "woke", even one game with a female protagonist seems to be too many for them.
badsectoracula 18 hours ago [-]
It isn't a lot but i wouldn't say it is rare either.
lo_zamoyski 1 days ago [-]
I doubt it was intentional, but in general, I am not impressed by that and don't find any value in that. Same with Hollywood's depiction of women knocking out guys twice their size. Unrealistic, ridiculous, and harmful.
kridsdale1 1 days ago [-]
You don’t need a penis to hold a gun.
canelonesdeverd 24 hours ago [-]
>Unrealistic, ridiculous
So, a videogame?
jimjimjim 21 hours ago [-]
not harmful. why should women in action films need to be held to a higher standard the men?
Hollywood's depiction of action movies in general is unrealistic. Stereotypical Good Guy gets in a fist fight with a Random Thug, and after trading blows for a while the Good Guy knocks out Random Thug and carries on with the rest of the movie without a problem. No bruising, no eye swelling shut, no broken ribs restricting movement or breathing, no loose teeth, no broken fingers, no sore wrists from mis-angled punches.
canyp 15 hours ago [-]
I don't even know what GP is smoking, but real fights are measured in milliseconds.
ferguess_k 1 days ago [-]
I find the most interesting things are the internal tools -- like the Python script to generate the gib animation, or the other Python script to generate 2D spritesheet from Blender. OP is definitely a 10x engineer who can also do good arts. This is very rare IMO. I'm very surprised to find that OP has consistent art direction.
kridsdale1 1 days ago [-]
It seemed, as a fan of the genre in the 90s, like these Renaissance Engineers were behind every major hit. I remember some of their names, they are true artists.
I have no idea the names of nearly anyone but a CEO or lead Director in the games industry of the past 15 years.
ferguess_k 1 days ago [-]
As a side note, I checked OP's other projects, and looks like he/she was already OK with arts from earlier on:
This is so great. Another fun trick we used in the 90s was palette animation -- by swapping the palette you can create incredibly cool effects at a low runtime cost.
shakow 18 hours ago [-]
Indeed, and I highly recommend this website for some stunning examples of the technique.
Changing the pallette mid-frame is fun, too. You have to pay a lot more attention to timing since you don't have a copper (like the Amiga) on the PC, but it's still feasible.
ferguess_k 22 hours ago [-]
I recall that Diablo 1 (and 2) has a lot of enemies that are essentially the same sprite but different palette. Is it the same trick?
keithnz 20 hours ago [-]
it used to be a hardware thing, so if your pixels were represented by a nibble, and the definition of the color for each of the 16 possible value is in table the hardware references, you just update that table (on a vsync, or even an hsync) and you could get cool animations effects (for the time)
random example from the Atari 800xl https://www.youtube.com/watch?v=uPjLZ4MVKCc (you can see how slow it is to draw a scene, but the animation effect due to pallete rotation is really fast).
So refreshing to have this NOT read a few pageS IN; words to the effect of.. “and the I asked Claude to build most of it for me then set to tweaking a few parts at the edges before asking Claude to write up this blog post”
phkahler 1 days ago [-]
>> What this actually means is, the constraints I have foolishly imposed upon myself are as follows....
Those kind of constraints can lead to increased creativity, and can also influence the overall style of a game. It's part of the reason early 80's arcade games had so much diversity.
gotski 1 days ago [-]
This is terrific. I love reading about the creative process involved in a project like this, finding cool solutions to self-imposed boundaries.
I think the mix of highly rational reasoning and "it just feels right" is a killer combo too, it gives a rigorous basis for a lot of the decisions made, while also allowing for a strongly personal aesthetic to emerge. Very cool indeed.
mysterydip 1 days ago [-]
As a fellow 3d-engine-with-foolishly-unreasonable-constraints developer, I love the detail in the explanations here and seeing the process you went through.
boricj 1 days ago [-]
I'm tinkering with a voxel space rendering tech demo as a PlayStation homebrew. After one weekend of work I'm getting decent results (like, 10-15 FPS) and I've yet to use the DMA, the GTE or even polylines primitives.
It's refreshing to dust up trigonometry and good old low-level optimization tricks. When the scratchbuffer has 1 KiB and the stack can only use a fraction of that, it makes me realize how spoiled I'm at work with the microcontrollers we have, with threads being allocated 8 KiB of stack and backtraces with over 50 functions of C++ templates on it.
hankbond 18 hours ago [-]
I was genuinely surprised how good the render -> quantized sprite looked. That quick conversion made them look crispy.
canyp 15 hours ago [-]
Ironically, the image showing the graph that does that transformation could have gone through the pipeline as well.
I'd be curious to know in more detail what exactly is going on there. I guess the box sharpening is where most of the beef is.
zackmorris 23 hours ago [-]
We randomly chose magenta as our transparent pixel for shareware games too!
I consider 1993 the last "good" year of the pre-internet age. The web didn't go mainstream until around 95, and 94 felt like a liminal year (dunno why). In 93 one could still wrap a plaid shirt around one's waist without fear of ridicule. Grunge and alternative music hadn't quite landed in rural America yet, although we didn't know what we were missing. The Telecommunications Act, Digital Millennium Copyright Act (DMCA), Gramm-Leach-Bliley Act, USA PATRIOT Act, and so many other regressive/draconian laws hadn't passed yet to create the wealth inequality consuming the American Dream today. Although the Grand Upright Music vs Warner Bros decision had happened in 91 in an attempt to destroy hip-hop for racist reasons under the guise of protecting copyright. The Rodney King beating had happened the year before, but the OJ trial was still 2 years away. We were blissfully ignorant of the very ignorance and hate that would put us on this alternate timeline. It was like living in the Shire before the War of the Ring.
I can't stress enough how games like Wolfenstein 3D and DOOM completely blew our minds. They came out about 6-7 years before The Matrix, so the closest conceptual framework we had for it was probably The Lawnmower Man. Virtua Racing and Virtua Fighter came out about that time, but somehow couldn't compare. I remember using a drafting program on a 33 MHz PC with a 16 color monitor in drafting class, and DOOM revealed that even then, computers were running hundreds of times slower than they were capable of (millions of times slower today).
If I could go back to any time with what I know now, it would be spring of 93.
zackmorris 59 minutes ago [-]
Sorry, false memory - I remembered the full story in all of its gory details after sleeping on it.
We did use magenta and colors near it for reserved pixels that would never be seen onscreen, but in our case it was for color animation. The Mac couldn't do full-screen palette animation in a way sanctioned by the OS, because Apple arbitrarily inserted an internal wait for the vsync monitor refresh interval in all of its palette functions, with no way to disable it or directly access the low memory variables that controlled the color lookup table (CLUT) like on the PC. So an empty main loop with palette animation ran at 60 fps, but doing any draw calls at all caused a timing miss which dropped it to 30 fps, while the CPU sat at about 50% idle. Our games redrew the whole screen anyway, so we opted to translate pixel colors on the fly via our own lookup table instead.
Apple also didn't provide OS calls for page flipping (to draw the next frame of animation while the current one is shown to double the frame rate), probably by design to maintain the Mac's image as a "professional" desktop computer, because such tricks were well-understood in the gaming industry. Or video resolutions below 640x480 (sometimes 512x384 on certain models).
Apple also tended to ship machines with half-width busses (supposedly to reduce cost) like the Mac LC, which reduced memory bandwidth so much that full-screen scrolling was difficult to achieve.
Those decisions prevented the Mac from becoming a performant gaming system, even though the RISC-like 68k chip with its numerous registers, predictable instruction set format and unsegmented memory were far superior to PC architecture at the time IMHO.
Later PowerPC chips like the 603e had a cache misalignment issue where double-width 8 byte memory copies that weren't 8 byte aligned ran at about half speed (probably using 2 copies internally) so I think we had to drop down to single-width 4 byte copies or use a cache hint function to disable caching while copying image buffers, which ran slightly slower.
Notable snafus included years-long delay of support for newer OpenGL versions, so we were stuck with fixed-pipeline 1.x calls long after the PC was exploring shaders. Then iOS only supported OpenGL ES, with no real reason not to offer an ES compatibility layer on desktop, necessitating support of 2 codepaths. Instead of remedying that stuff, they introduced Metal, which nobody asked for.
Not to mention deprecating wide swaths of the OS, forcing rewrites from MacOS 8 to 9 (Carbon), then from 9 to X (Cocoa), then from MacOS to iOS (Objective-C and Swift). Don't forget the 68k to PowerPC to Intel to ARM chip migrations, which forced developers to be aware of endianness issues, which greatly increased the complexity of reading/writing binary files.
Combining all of those permutations, MacOS software would often only survive perhaps 3 years before needing a rewrite. I probably have 10 times as many applications (mostly old games) on my Mac with a no-smoking sign through them as runnable applications.
I'm reminded of the expression "lemons for the price of peaches". The outer elegance of the Mac obfuscated the underlying byzantine layers. Denial became woven into the Mac experience, so much so that developers took a certain level of trauma to keep up appearances. I know I did. That's why I got out of the biz in the early 2010s after so many of our games that we put so much work into turned out to be commercial failures. We might have made 10 times more money targetting the PC, and conceivably 100 times more if we had cross-platform resources like Unity and Steam.
I bring this stuff up because rose colored glasses often obscure what really happened. Especially now with political insiders and the media producing so much revisionist history. Stuff we remember as cutting-edge manifested because the state of the art at the time was so abysmal.
I look around today and I see a whole lot of assumptions being made that this is all there is. That the current path of tech is the one true way. When nothing could be further from the truth. We're ruled by powerful duopoly forces presenting the illusion of choice, when all eggs are in the GPU basket. But do they use GPUs on Star Trek? Probably not.
dhosek 23 hours ago [-]
The last real graphic programming¹ I’ve done was in the late 80s targeting the Tektronics graphics mode of the Kermit terminal software on the PC.² It was all pretty much clear the screen and draw solid rectangles in 1-bit black and white. One of these days I’m going to join the twenty-first century.
⸻
1. I suppose some hand-written PostScript code might count as well, but I wouldn’t really count things like doing a simple function graph in python to explain something to my son as graphics programming.
2. This was for a DVI previewer running on an IBM mainframe running VM/CMS. As far as I know, this code is completely lost, which is probably a good thing.
trumpdong 1 days ago [-]
For some reason I irrationally like the posterization effect that's created when something is darkened to almost zero.
Agentlien 11 hours ago [-]
This is a cool project and I really like the author's technical and aesthetic choices of how to limit themselves.
But what really stood out to me is this line.
> a linear frame buffer where each pixel was represented by a single byte indexing into a palette of 256 colors.
Of course this is nothing new, but it just really struck me because I've been working on a blog post about texture representation on modern consoles and it is crazy how complex it has gotten: texture tiles, block compression, non-linear texel ordering (e.g. Morton order), ...
Panzerschrek 12 hours ago [-]
> The generation pipeline takes several inputs:
> a heightmap that defines the surface relief
> this is actually just used to generate the normal map, which is then used to bake in simple lighting and shadows
I don't think someone used this approach in 1993. Textures were drawn by hand. But I think it's still fine to use such modern way of generating textures, since it may produce better-looking result.
nticompass 1 days ago [-]
I respect the amount of work that goes into projects like this; I can't wait to be able to play it.
wuliwong 1 days ago [-]
I am not even a noob with game development. I dabbled with Godot a couple years ago and was making a funny weight lifter game, some sorta stat management sim. It was actually pretty fun but I didn't get past some pretty early working versions.
I thought I could really level up with Claude and I started working on a boxing game. It's been a total disaster. .·°՞(˃ ᗜ ˂)՞°·.
ogurechny 1 days ago [-]
Step 0 is missing: having a great taste. One look at the video example is enough to figure out that the author keeps things in balance and in style. Explanations of why pixel grid mismatch looks wrong, or why mismatch between texture density and geometric complexity (in both ways) looks horrible, or why smoothing does not blend with pixel art are then made in retrospect.
Some details are a bit too cool for 1993, though, and assume high frame rate (won't work that well at low fps). Smooth weapon animations with a lot of frames, tiny per-pixel effects on bullet holes and flash sprites, smooth movement and object position calculations that use precise math instead of fast rough estimates resemble Chasm: The Rift or Quake (the concept of idle animations, e. g. objects moving in the starting view of difficulty selection room, assumes that there is some performance to waste on details that make the world less empty).
Terr_ 24 hours ago [-]
> Well, it would work, but the result would look terrible because pixel scale is no longer consistent.
This is my complaint with a lot of "graphical enhancement" mods for games like Deus Ex.
Unless they touch everything, the inconsistent level of detail is worse than consistently low-res meshes/textures.
Panzerschrek 12 hours ago [-]
> We then choose the number of shade levels (32 in my case) meaning each color needs 31 darker variants
I suggest to use not only darker variants, but also brighter ones - for bright map areas and maybe for some lighting effects like flashlight.
kylemaxwell 1 days ago [-]
Every time I think about graphics programming, I think about how we did it in the mid 90s when I was in high school messing around with exactly these things. XOR operations to drive animations, writing directly to memory, etc. (Clearly I do backend stuff now...)
purple-leafy 22 hours ago [-]
Cool project! How hard was it to get the z levels (height) ??
I made a very similar project [0] in C 2 years ago, a chunked ray caster that could handle multiple height levels. Was one of my first C projects, pretty crappy but was fun.
Anyone have any ideas how to make it more memory efficient?
I'm impressed by your sprite pipeline and gibs animations. Your attention to detail and navigation of constraints have really paid off, I can't wait to play this sometime
blackhaz 1 days ago [-]
Everything is perfect here. The hero, the graphics, the title... <3
garganzol 21 hours ago [-]
I like the theme too. In general, author does not seem to follow typical rules. In my opinion, this is a huge bonus for him as an artist.
badsectoracula 1 days ago [-]
Nice, i've used similar approach for the lighting in Post Apocalyptic Petra[0] though i did use per-pixel LUT offset calculation[1] because it uses a generic 3D triangle rasterizer (the levels are based on grids like in Tomb Raider but they're rendered as triangles). Later i added sprite support for another gamejam but i never ended up finishing it and the sprite support is very rudimentary (and unoptimized - i just noticed i'm doing the LUT lookup for every pixel when drawing shaded sprites which isn't necessary).
I did write a tool for generating the sprites from 3D models though[2]. It uses plain old OpenGL 1.1 to draw the sprite and grabs the framebuffer directly. It is drawn fullbright so i can paint the lighting directly on the sprite's texture (using a Krita plugin i wrote[3][4] - the model is something i threw together with Blender's default generated UV since i didn't care for the details).
I wonder if doing some sort of postprocessing (after rendering with with shading) like you do with your game would help with the finer details since i also found that rendering from 3D models to sprites creates very "mushy" results most of the time because of all the details getting lost. I notice the colors also become more saturated after postprocessing in your examples, is this after it finds the closest color in the palette or the result of the postprocess? I'd like to keep the overall hue+saturation of the model so maybe doing post-processing on a grayscale render to shade the shadows/dark areas but keep highlights as-is and then multiplying that with the fullbright image would produce results that wont shift the saturation.
>I notice the colors also become more saturated after postprocessing in your examples, is this after it finds the closest color in the palette or the result of the postprocess?
It's the result of the Blender compositor postprocessing, just keep in mind it falls apart once you go low enough in resolution (it's an image space thing after all), so I'm not sure if that helps your case.
EDIT: Also, your project is very cool!
fabiensanglard 1 days ago [-]
Consider a premium, boxed version. I would buy it. And I think a lot other would. Maybe try a kickstarter to see how many are interested?
massifist 20 hours ago [-]
If there's enough room, you could add special palette indexes that stay
constant or diminish more slowly with distance. To give a glow effect for
lights, torches, etc. I always appreciated this effect in Quake.
EDIT: Oh nevermind. I guess brightmaps are more flexible.
cautiouscat 22 hours ago [-]
Maybe the recent final update to Destiny has already taken over my brain but if Marko is a Destiny fan, he has a great GitHub username.
This is an extremely detailed article on every level and I can’t wait to deep dive into it. Marko really nailed the “old” look but it still looks fresh and new.
renyicircle 1 days ago [-]
I really loved that article. Creating games always seemed so daunting to me since I don't know a lot about how it's done, there are so many different processes involved. The solutions described here are so satisfyingly compact and so easy to understand given the simple constraints, and yet they produce an actual game that looks nice.
Panzerschrek 12 hours ago [-]
> Catlantean 3D is a traditional raycaster. The map consists of tiles which are all identical in size;
It's sad. That's why I never finished playing Wolfenstein 3D - it looks too boring. In the other hand I enjoy playing Doom, mods for it and games using its engine.
I hope the author can still add some improvements to allow such boring look typical for raycaster engines.
mrob 1 days ago [-]
In the final video, it looks like the destructible vases take several shots to destroy. IMO, they should only take one. Real life vases only take one, so requiring more makes the gun feel weak. It seems to be cosmetic anyway, so there's no game balance reason to require more.
low_tech_love 23 hours ago [-]
Looks really cool, please release episode 1 as shareware! (Or a demo on Steam works too)
progforlyfe 1 days ago [-]
Much respect -- at first glance when I saw the animated gif I thought this was just a project making assets from scratch for an existing game engine (e.g. Doom or Wolf 3D) but then I realize it's creating all the game code from scratch too! (But using similar techniques from the old days). Amazing work.
sgt 1 days ago [-]
Really cool. It's also something LLM's are ridiculously bad at, so you kinda have to do it properly.
badsectoracula 1 days ago [-]
As a side note, the visual style in the game reminds me a lot of Exhumed / Powerslave :-).
trashb 1 days ago [-]
This game looks great I really like the style it is inspiring.
The author seems to consider open-sourcing the engine, I would also be interested in the mentioned scripts for asset creation. Those scripts would make a great toolset for asset creation in this style.
microtonal 23 hours ago [-]
@sklopec any chance you have a Mastodon or maybe Bluesky account where we can follow your work? Would love to follow development and buy your game when it's out.
jonoxtoby 1 days ago [-]
This is a great write-up of your process and behind-the-scenes peek at the making of what looks to be a really fun game! Can't wait to play and delve into the code once you release it.
wonkyfruit 21 hours ago [-]
Genuinely lit. Gives me a whole new appreciation for the games I played as a kid, and John Carmack. Nice project :D
Levitating 1 days ago [-]
I love this! I have been working on a similar project, recreating the originale BBC Elite but with multiplayer networking. Though I have not limited myself as much (I use SDL).
cosiiine 1 days ago [-]
This is a wonderful deep dive into your project. I'm early days on creating pixel art style procedural art systems, and this gives me plenty to think about.
binaryturtle 1 days ago [-]
With the title I was expecting some notes about DeluxePaint, but it was still a nice read nonetheless. Wish you much success with the game! :-)
jiffygist 23 hours ago [-]
Will definitely play when it's released. Doom is my favourite game and I enjoy playing it at 320x200.
nopurpose 24 hours ago [-]
What does he mean by inconsistent pixel scale when he talks against increasing sprite resolution?
pragma_x 24 hours ago [-]
Just a guess: if you want to scale a sprite at anything less than a whole ratio (e.g. 1.5, 0.7, etc), you have to choose pixels to drop out and pixels to repeat , on some pattern that looks good. There are going to be scaling ratios that look like a hot mess, especially at a low resolution like 320x240.
mrob 24 hours ago [-]
In context, it's talking about sprites that are going to get non-integer scaled anyway (in-game pickups), so it's just about maintaining a consistent detail level. If those specific sprites had their resolution increased, everything else would need its resolution increased to match them.
Inconsistent resolution isn't necessarily a bad thing, e.g. Elite for the BBC Micro changes video mode part way down the screen so it can display both high resolution monochrome wireframe 3D and a lower resolution color map/UI below, but it's not idiomatic to the MS-DOS style this game is going for.
harel 1 days ago [-]
This is beautiful. I wish one day I'll have to time for a project like that. Looking forward to buying it on Steam.
TheAmazingRace 21 hours ago [-]
It doesn't say in the blog post, but will this be released for MS-DOS?
Felger 20 hours ago [-]
Well here's goes my self-esteem again. I hate you ! :D
(Nice job, seriously)
ant6n 11 hours ago [-]
I personally am not a big fan of the banding effect due to small number of light levels. One way to reduce that would be to introduce a 2x2 dithering matrix grid across the whole screen that introduces small “luxel” deltas like 0.5, -0,5; 0.5, -0.5. Some pixels will be brighter, some darker, reducing the banding. Could also try different matrices.
reifcode 1 days ago [-]
one of my very first solo projects during high school was writing a wolfenstein-like raycaster from scratch. I still hold some very fond memories of programming it, arguably one of the moments I fell in love with the craft
vkaku 5 hours ago [-]
This author doesn't publish code, makes yet another Doom like Game, calls it not an AI slop. To the author's credit, seems to have made this 7 years ago, https://www.youtube.com/watch?v=YQ7aApNDPQc and then gave up working on it till recently.
It doesn't look like slop at all, and it looks like it actually is. Could have been used to generate art assets, or finish something author did not have the energy to do before. Nobody cares if that was the case. Why the hate towards AI even?
functionmouse 1 days ago [-]
cool cat game
what's unreasonable about this though?
zerr 1 days ago [-]
I hope they leveraged Mode X :)
mempko 1 days ago [-]
Wow, this takes me back of making my own software renderer and game engine as a teen in the 90s. Then OpenGL came out and fixed pipelines and some of the cool magic of doing anything with pixels disappeared (until pixel shaders came back). One cool rendering technique you don't see much today is voxel graphics.
pjs_ 22 hours ago [-]
looks really beautiful, amazing job
test1072 22 hours ago [-]
it's my birth year
wazoox 1 days ago [-]
That's beautiful. I hope it will run on a 486DX2 :D
relativeadv 1 days ago [-]
Bravo! Wonderful read.
The comments here are a cesspool unfortunately. People bickering about pronouns used for cats, how many shots it takes for a vase to explode, or whether or not some circa-1993 software was used or mentioned.
perfect_wave 24 hours ago [-]
[dead]
RishiByte 22 hours ago [-]
[flagged]
WhoAteSnorlax 21 hours ago [-]
[dead]
tobadzistsini 1 days ago [-]
Unpopular opinion but the author remarks that the cat is female but uses "it" as pronouns. Human garbage.
akoboldfrying 16 hours ago [-]
I'm tempted to call people who get upset over harmless pronoun jokes "human garbage", but the truth is that would be overkill. "Irksome" covers it.
mg794613 1 days ago [-]
There is nothing wrong with using AI.
What I don't like is to see claims like "no AI slop"
And yet it's riddled with emdashes and language "by hand"
Seeing the skills of the writer, he definitely should be able to, but then I don't understand the claim.
ch_sm 1 days ago [-]
I don’t know. Em-dashes are normal punctuation. The prose on the site doesn‘t strike me as particularly AI-y, but of course I might be wrong. Generally speaking, if the person wants to not use AI and tell people that, thats fine by me too.
engcoach 1 days ago [-]
We're getting to the point that building something with AI doesn't really indicate skill. So, for a prestige project, there is great value in avoiding AI use.
Supermancho 1 days ago [-]
From the article they list a bunch of arbitrary constraints...
> If this sounds unreasonable to you, that is because it is.
Those listed, are tame. I don't understand this kind of faux modesty.
> My goal was to build a complete, shippable first-person shooter using techniques that were common in the early 90s
Goes on to explain how they used 3D blender...which wasn't available until 1998.
A vanity cat project being tailored and submitted for nostalgia clickbait. I don't think there's anything useful to take away from this other than some color shade selection ideas.
mrob 23 hours ago [-]
>Goes on to explain how they used 3D blender...which wasn't available until 1998.
In the early 90s, there was enough money in this kind of software that you could have hired a specialist 3D artist to use the software that was available at the time, e.g. LightWave 3D. When it's only a single-person project, I think it's reasonable to stick with what you know.
ogurechny 18 hours ago [-]
You look like you are completely unaware of the wave of big and small early nineties games that used flat shaded 3D renders for art, sprites, and full motion video segments. Unlike fully textured polygons, they could be rasterised quickly on older or entry level Silicon Graphics workstations (or cheaper alternatives, but with more sweat). It was one of the distinctive styles of that era.
xyzsparetimexyz 1 days ago [-]
It'd be more interesting if you made a similar looking game using modern APIs imo
sklopec 1 days ago [-]
How so? Doing this with modern OpenGL would be much simpler than the software rasterizer solution.
I think I'm gonna have to do it anyway, because some players claim they get nausea when playing at such low resolution (320x240), and the only way to give them higher resolutions that perform reasonably is to have it hardware accelerated.
Renderer is abstracted away already, but the real difference would probably be occlusion culling... With raycasting, I get it for free, but if I'd go down the hardware accelerated path I'd have to pick something more clever.
Raycasting and software rendering in general tends to scale poorly with resolution, even with vectorization and all the bells and whistles of modern CPUs.
badsectoracula 1 days ago [-]
Unless you plan on rendering the level on some very retro hardware (think S3 Virge, maybe Voodoo 1) you can render the entire level in OpenGL with just zbuffer and alpha tested sprites and it'll run perfectly fine - if anything with such low polycount, chances are you're going to make the renderer slower by trying to do occlusion culling on any GPU released in the 21st century :-P. If you pack the geometry in a few vertex buffers (for each unique texture) even per-frame, you'll get four digit FPS in any relatively modern GPU.
As an example this[0] video shows the benchmark from Post Apocalyptic Petra running on my previous GPU (RX 5700 XT) which all it does is build a per-frame (client-side) vertex-buffer in OpenGL 1.1 (the engine was made for actual retro PCs running DOS and Win9x so it does some rudimentary occlusion culling but that mainly affects 90s hardware, not anything released since 2000 or so). If anything, the rendering has so little overhead that half of the framerate is "eaten" by the FPS counter overlay :-P.
Thinking about modern games, a single character model probably has more vertices than my entire level (and yours probably), so it's definitely reasonable to expect occlusion culling for such simple geometry might actually reduce performance rather than increase it.
badsectoracula 1 days ago [-]
Yeah, even this model[0] i made a few years ago for a game i wanted to make for the OG xbox (which has a GeForce3-like GPU) has ~2230 triangles and the entire first level of Post Apocalyptic Petra is ~5800 triangles, so you could say that even a turn of the century 3D character has more or less the same polycount as an entire 90s level (the game i wanted to make would have many characters on screen so i kept the polycount low but i've heard games having 5-6K character or more - e.g. Kingdom Under Fire had ~10K triangles for the main character and a game like Dead or Alive where there are few characters on screen had 15-20K triangles).
Meanwhile more current games have much higher polycounts, easily going above 100K triangles - e.g. Dante from DMC5, a ~7 year old game, apparently has ~190K triangles and that had to run on the more anemic PS4/XBone hardware :-P (though i'm not sure if it used the full 190K model there or some cut down version).
I rendered some Source engine levels on a shitty laptop in 2012ish and they still rendered at perfectly acceptable FPS (30+) just by rendering all the geometry in the level in one shot.
pjc50 1 days ago [-]
The synthesis technique would be to build the DOOM-style BSP tree and then construct a bunch of meshes for use depending on which portal space you're currently in, but .. as you say, you don't need to do that because it's at most a few hundred polygons.
xyzsparetimexyz 1 days ago [-]
Sure, but it becomes a question of how far you can push things. Maybe you raytrace the whole thing. Maybe there's some fractal geometry going on. Maybe you use a fisheye lens projection. Maybe your levels are dynamically tesselated. Maybe you have to do a few fancy tricks to achieve equivalent texturing etc.
But ignoring the GPU you have on your system is boring
jonoxtoby 1 days ago [-]
Writing a retro-inspired game using retro approaches despite all the modern options is precisely what makes this interesting.
Rendered at 17:53:22 GMT+0000 (Coordinated Universal Time) with Vercel.
I feel like the idea of fixed-point is under-utilized and very under appreciated. There are loads of applications where this is a better choice, let alone more performant.
The Build engine didn't use BSP, it treated connections between sectors as portals and rasterized the walls as (90 degree rotated) trapezoids while performing clipping against those portals. This allowed it to have dynamic wall geometry (e.g. moving trains, rotating light fixtures, etc) as well as "room-over-room" setups as long as you couldn't see both rooms at the same time (in both Blood and Shadow Warrior they found a workaround for it allowing to create more "3D" spaces by making identically shaped sectors with the floor of one sector acting as a portal to the ceiling of the other sector - supposedly this wasn't "natively" supported by the engine, but it was flexible enough for the game studios who used it -without even having access to the source- to do it themselves).
The first level of Duke Nukem 3D does use a few Build tricks - e.g. another one is that sprites can be "axis aligned" instead of following the camera and they can also have collision - this can be used to create rudimentary 3D geometry by treating each sprite as an axis aligned quad and in the first level it is used to make a bridge between two buildings (right before the level exit button).
If I were to do a raycaster today, I would use convex sectors with portals, basically like duke nukem, but constant wall heights. You can do drawing very simply by just doing a linear pass across the sector, recursively stepping into other sectors.
Then you can at least do arbitrary level geometries.
The engine used Build/Doom-like maps and would simply raycast against the camera's current sector (sectors could be any shape not just convex) and used connections between sectors as portals to recursively follow the (2D) map until it hit a solid wall - so basically Build's portal rendering approach except using raycasting instead of trapezoid rasterization. It could also do sprite rendering (you could have both sprites facing the camera and "aligned" sprites that could be used for decals) and even had some simple 3D model rendering (the triangles were sorted and clipped against the portal during rasterization). Unfortunately Flash isn't available in browsers anymore and Ruffle isn't compatible with it (it can run the engine -much slower than real Flash- but the palette is all wrong), so i took some shots using the standalone Flash "projector"[1][2][3][4]. Also making maps for it was certainly much more laborsome than making maps for a Wolf3D-like game and that combined with me losing interest in making Flash games meant i never made a game with it.
[0] https://www.youtube.com/watch?v=Z81NhEbl3q8
[1] http://runtimeterror.com/pages/iv/images/01feb493af6dd3184b8...
[2] http://runtimeterror.com/pages/iv/images/136a8753b211ed7e3d1...
[3] http://runtimeterror.com/pages/iv/images/84c2012258982b82053...
[4] http://runtimeterror.com/pages/iv/images/e94cc334c7735e1aacb...
Btw, 286 played wolfenstein rather poorly. The 386 is rather more appropriate.
Wolfenstein was built in a couple of months by a then 21-year-old Carmack. He didn't focus on optimizing levels until Doom.
It's true that Carmack has said several times, including in the readme to the source release of Wolf3d [0], that a BSP-based renderer might be faster than raycasting. He used a BSP tree based renderer for the SNES port of Wolf3d because the CPU was even slower, so I suppose that answers it! There's also a note in the GEBB page 164 from Carmack where he says it was slower than "looping through a few long wall segments". [1]
Early alpha versions of DOOM used a sector-based rendering technique, maybe like what you're describing, which ultimately was too slow [2]][3]. Then Carmack switched to BSP trees after doing the Wolf3d SNES port.
I think it would be pretty interesting to implement the same game with both a raycasting approach and a BSP or Build-style portal/sector approach and compare performance on a 386. DOOM ran terribly on a 386 but it did a lot more than Wolf3d, so it's not a great comparison. Catacomb 3D didn't use raycasting (it used a wall span rendering techniqe) and ran better than Wolf3d on similar hardware, but it had a bunch of glitches. But Carmack says they were due to lack of experience rather than the technique itself.
Anyway thanks for challenging my assumptions. This'll go on my todo list!
[0] https://github.com/id-Software/wolf3d [1] https://fabiensanglard.net/b/gebbwolf3d.pdf [2] https://youtu.be/NnkCujnYNSo?t=1592 [3] https://doomwiki.org/wiki/Doom_rendering_engine
Blake Stone Rise of the Triad used later versions of the Wolf3D engine and had textured floors/ceilings
> Doom and IIRC Duke Nukem as well used a BSP engine which was much more flexible
Duke Nukem (Build engine) did not use BSP
https://www.jonof.id.au/forum/topic-137.html#msg1548
To work around this, people used an unofficial tool to patch the maps to support transparent water:
https://vispatch.sourceforge.net/
With the data structure being more efficient, and doing less overall work, I think this part of the Doom/Duke engine might even be faster than than Wolf3D
For floors, unfortunately there's no such luxury, and if I remember correctly DOOM subdivided floors into patches, and only did proper perspective at the corners, and interpolated inbetween.
The BSP may have led to some floor subdivisions, especially as it needs convex sectors. I don't remember if the engine would coalesce adjacent floor spans into a single one, but I hope it did.
And it looks to me like we are mapping each row with a constant y, calculating the "distance" (thus scale factor) only once using just the vertical slope for the row.
So while it didn't have custom processors for sprites and background layers it meant there wasn't a rigid fixed function nature to what the PC could do.
By the mid-late 90's with dedicated 3D processor this wasn't an issue any more but there was a brief time in the early 90's where there was this wonderland of unique visual rendering.
Though your extender could make things a little more annoying on that front :-P
(DJGPP and Free Pascal -which use the same "go32" extender by DJ Delorie- do not do a full linear mapping so you need to do a bit more juggling to get stuff on screen there)
Also some (more) free (open source) 16-bit C-compilers now, like the ia16 gcc port and Microsoft's C compiler included in the MS-DOS repo on GitHub.
Not that 32-bit extenders do not come with some advantages, but I enjoy the simplicity of 16-bit.
If you want to get inspired by what can be done with palletized framebuffers check out http://www.effectgames.com/demos/canvascycle/ (click Show Options) and the GDC presentation by the artist https://youtu.be/aMcJ1Jvtef0
With that you can fire up https://github.com/mriale/PyDPainter for that classic Deluxe Paint IIe vibe. Or, https://www.aseprite.org/ for something more modern.
But maybe a software renderer and SDL_Texture could preserve it?
The even faster version, opts aside, would be to initialize the pointer at y*screenRect.w and ++ at every loop to avoid the addressing arithmetic.
Take a look, GCC and Clang go further than these suggestions by adding screenRect.w to the pointer each iteration to avoid the multiplication: https://godbolt.org/z/YfroqK7T6
Writing anything but pixels[y*screenRect.w + x] in an attempt to be faster, without checking the assembly first, is obfuscation.
(For what it's worth, you can beat the compiler by using *pixels++. I didn't profile the code to check it actually was faster in practice however.)
It's not that rare, is it? Off-hand, and very mainstream; Perfect Dark, Mirrors Edge, Dishonored (don't remember if it's the first or second one), Metroid and more are all kind of "shooters" with female protagonist, although maybe Mirror's Edge is more just "first-person" than "shooter" to be 100% accurate.
Not to mention the large selection of "RPG + FPS" where you can be either man or woman.
---------
Seems the author also realize the thing with the pattern and likely gender of the cat:
> After all, I do need to give the protagonist his fair share. [image] (Yes, I know it's a female, but call it convention rooted in dialect.)
Edit: I completed forgot Chell from Portal, too!
https://unrealarchive.org/wikis/the-liandri-archives/Prisone...
https://unreal.fandom.com/wiki/Prisoner_849
> The character of Prisoner 849 is commonly speculated to be Gina, as her model (Female 1) and skin are the first character to appear in alphabetical order; this is even reinforced by UnCreature giving the female player a bio while the male player bio just reads "See Female Player". However, the character of Prisoner 849 is completely up to the player's choice, hence the use of neutral nouns in this article.
If you tally all the FPS releases in a given year, a supermajority are going to have male protagonists.
Mirror's Edge has a female protagonist, but it's not an FPS (First Person Shooter). It's a parkour simulator which technically lets you shoot a gun in limited sections of the game, but the protagonist is a pacifist and you get a bonus for decommisioning guns rather than firing them.
If the thread would like some hard data:
- 19,526 games on Steam tagged "female protagonist" https://store.steampowered.com/search/?tags=7208&ndl=1
- 13,578 games on Steam tagged "FPS" https://store.steampowered.com/search/?tags=1663&ndl=1
- 727 games on Steam tagged both "female protagonist" and "FPS" https://store.steampowered.com/search/?tags=7208%2C1663&ndl=...
So it looks like the two categorisations, for the most part, don't intersect.
Notable counterexamples would include Rise of the Triad, Ion Fury, No One Lives Forever, Wolfenstein: Youngblood and Far Cry 6, but definitely rare. You'd be clutching at straws to describe Portal or Alien: Isolation as FPS (they're a puzzle game and survival horror game respectively), likewise the Resident Evil / Clock Tower / Fatal Frame / etc. games with the novelty option of switching to first-person view, they're naturally third-person perspective. Left 4 Dead has one female character out of four you can play. You might count that one DLC for Bioshock: Infinite where Elizabeth gets a shot (https://www.youtube.com/watch?v=1E1lh-pb6Is). You might count the few FPS RPGs that there are with customisable characters (so yes Fallout, but not Mass Effect as it's third-person). But female protagonists are massively more prevalent in survival horror, metroidvania, third-person shooters (Tomb Raider, Monster Hunter, Horizon Zero Dawn, etc) and other genres besides FPS.
You probably didn't play many FPS recently: from the top of my mind, CS2, Battlefield {1, V, 6}, CoD {BO3, Vanguard, MWIII}, Control, the Borderlands, Far Cry {5, 6}, CP2077, Fallout {3, NV, 4}, Destiny, Prey, Valorant, Rainbow 6, Apex, Overwatch, all have female player characters.
And if CS2/CoD/BF/Valorant/Destiny/Apex have female players, that's more or less 90% of the current market.
I took a glance at the the most played FPS list from Steam[0], but I was too lazy to scroll far enough to find one without a playable female character.
[0] https://steamdb.info/charts/?tagid=1663
Choosing one specific example when I also made more recent ones, isn't such a big dunk you think it is.
> If you tally all the FPS releases in a given year, a supermajority are going to have male protagonists.
Sure, I agree, I'm not saying it's more popular, just that I don't think it's that rare, but I guess ultimately I'm a bit nitpicky (sorry) and we're just disagreeing with the specific definition of "rare".
No, this isn't a Perfect Dark game
[0] https://store.steampowered.com/app/1592280/Selaco/
[1] https://store.steampowered.com/app/1693280/Supplice/
[2] https://store.steampowered.com/app/1378290/The_Citadel/
[3] https://store.steampowered.com/app/3371240/Beyond_Citadel/
[4] https://store.steampowered.com/app/2443360/Zortch/
[5] https://store.steampowered.com/app/3807500/Zortch_2/
[6] https://store.steampowered.com/app/1051690/Nightmare_Reaper/
[7] https://store.steampowered.com/app/1785940/COVEN/
[8] https://store.steampowered.com/app/1406780/Viscerafest/
[9] https://store.steampowered.com/app/1072150/Hedon_Bloodrite/
"boomer shooter" + "female protagonist": 106 matches.
So a bit less than 1/10 of the games tagged with "boomer shooter". With your caveats above about being able to choose a gender, or a single brief segment where you're a lady in a game where you're mostly a dude. Is that a lot? I dunno, doesn't feel like a lot to me. Probably feels like a lot to the people who inevitably show up in the Steam discussions of any successful game that makes you be a lady for most of its length and complain about it being "woke", even one game with a female protagonist seems to be too many for them.
So, a videogame?
Hollywood's depiction of action movies in general is unrealistic. Stereotypical Good Guy gets in a fist fight with a Random Thug, and after trading blows for a while the Good Guy knocks out Random Thug and carries on with the rest of the movie without a problem. No bruising, no eye swelling shut, no broken ribs restricting movement or breathing, no loose teeth, no broken fingers, no sore wrists from mis-angled punches.
I have no idea the names of nearly anyone but a CEO or lead Director in the games industry of the past 15 years.
https://staniks.github.io/articles/inferno/
https://staniks.github.io/articles/worship/
http://www.effectgames.com/demos/canvascycle/
random example from the Atari 800xl https://www.youtube.com/watch?v=uPjLZ4MVKCc (you can see how slow it is to draw a scene, but the animation effect due to pallete rotation is really fast).
Those kind of constraints can lead to increased creativity, and can also influence the overall style of a game. It's part of the reason early 80's arcade games had so much diversity.
I think the mix of highly rational reasoning and "it just feels right" is a killer combo too, it gives a rigorous basis for a lot of the decisions made, while also allowing for a strongly personal aesthetic to emerge. Very cool indeed.
It's refreshing to dust up trigonometry and good old low-level optimization tricks. When the scratchbuffer has 1 KiB and the stack can only use a fraction of that, it makes me realize how spoiled I'm at work with the microcontrollers we have, with threads being allocated 8 KiB of stack and backtraces with over 50 functions of C++ templates on it.
I'd be curious to know in more detail what exactly is going on there. I guess the box sharpening is where most of the beef is.
I consider 1993 the last "good" year of the pre-internet age. The web didn't go mainstream until around 95, and 94 felt like a liminal year (dunno why). In 93 one could still wrap a plaid shirt around one's waist without fear of ridicule. Grunge and alternative music hadn't quite landed in rural America yet, although we didn't know what we were missing. The Telecommunications Act, Digital Millennium Copyright Act (DMCA), Gramm-Leach-Bliley Act, USA PATRIOT Act, and so many other regressive/draconian laws hadn't passed yet to create the wealth inequality consuming the American Dream today. Although the Grand Upright Music vs Warner Bros decision had happened in 91 in an attempt to destroy hip-hop for racist reasons under the guise of protecting copyright. The Rodney King beating had happened the year before, but the OJ trial was still 2 years away. We were blissfully ignorant of the very ignorance and hate that would put us on this alternate timeline. It was like living in the Shire before the War of the Ring.
I can't stress enough how games like Wolfenstein 3D and DOOM completely blew our minds. They came out about 6-7 years before The Matrix, so the closest conceptual framework we had for it was probably The Lawnmower Man. Virtua Racing and Virtua Fighter came out about that time, but somehow couldn't compare. I remember using a drafting program on a 33 MHz PC with a 16 color monitor in drafting class, and DOOM revealed that even then, computers were running hundreds of times slower than they were capable of (millions of times slower today).
If I could go back to any time with what I know now, it would be spring of 93.
We did use magenta and colors near it for reserved pixels that would never be seen onscreen, but in our case it was for color animation. The Mac couldn't do full-screen palette animation in a way sanctioned by the OS, because Apple arbitrarily inserted an internal wait for the vsync monitor refresh interval in all of its palette functions, with no way to disable it or directly access the low memory variables that controlled the color lookup table (CLUT) like on the PC. So an empty main loop with palette animation ran at 60 fps, but doing any draw calls at all caused a timing miss which dropped it to 30 fps, while the CPU sat at about 50% idle. Our games redrew the whole screen anyway, so we opted to translate pixel colors on the fly via our own lookup table instead.
Apple also didn't provide OS calls for page flipping (to draw the next frame of animation while the current one is shown to double the frame rate), probably by design to maintain the Mac's image as a "professional" desktop computer, because such tricks were well-understood in the gaming industry. Or video resolutions below 640x480 (sometimes 512x384 on certain models).
Apple also tended to ship machines with half-width busses (supposedly to reduce cost) like the Mac LC, which reduced memory bandwidth so much that full-screen scrolling was difficult to achieve.
Those decisions prevented the Mac from becoming a performant gaming system, even though the RISC-like 68k chip with its numerous registers, predictable instruction set format and unsegmented memory were far superior to PC architecture at the time IMHO.
Later PowerPC chips like the 603e had a cache misalignment issue where double-width 8 byte memory copies that weren't 8 byte aligned ran at about half speed (probably using 2 copies internally) so I think we had to drop down to single-width 4 byte copies or use a cache hint function to disable caching while copying image buffers, which ran slightly slower.
Notable snafus included years-long delay of support for newer OpenGL versions, so we were stuck with fixed-pipeline 1.x calls long after the PC was exploring shaders. Then iOS only supported OpenGL ES, with no real reason not to offer an ES compatibility layer on desktop, necessitating support of 2 codepaths. Instead of remedying that stuff, they introduced Metal, which nobody asked for.
Not to mention deprecating wide swaths of the OS, forcing rewrites from MacOS 8 to 9 (Carbon), then from 9 to X (Cocoa), then from MacOS to iOS (Objective-C and Swift). Don't forget the 68k to PowerPC to Intel to ARM chip migrations, which forced developers to be aware of endianness issues, which greatly increased the complexity of reading/writing binary files.
Combining all of those permutations, MacOS software would often only survive perhaps 3 years before needing a rewrite. I probably have 10 times as many applications (mostly old games) on my Mac with a no-smoking sign through them as runnable applications.
I'm reminded of the expression "lemons for the price of peaches". The outer elegance of the Mac obfuscated the underlying byzantine layers. Denial became woven into the Mac experience, so much so that developers took a certain level of trauma to keep up appearances. I know I did. That's why I got out of the biz in the early 2010s after so many of our games that we put so much work into turned out to be commercial failures. We might have made 10 times more money targetting the PC, and conceivably 100 times more if we had cross-platform resources like Unity and Steam.
I bring this stuff up because rose colored glasses often obscure what really happened. Especially now with political insiders and the media producing so much revisionist history. Stuff we remember as cutting-edge manifested because the state of the art at the time was so abysmal.
I look around today and I see a whole lot of assumptions being made that this is all there is. That the current path of tech is the one true way. When nothing could be further from the truth. We're ruled by powerful duopoly forces presenting the illusion of choice, when all eggs are in the GPU basket. But do they use GPUs on Star Trek? Probably not.
⸻
1. I suppose some hand-written PostScript code might count as well, but I wouldn’t really count things like doing a simple function graph in python to explain something to my son as graphics programming.
2. This was for a DVI previewer running on an IBM mainframe running VM/CMS. As far as I know, this code is completely lost, which is probably a good thing.
But what really stood out to me is this line.
> a linear frame buffer where each pixel was represented by a single byte indexing into a palette of 256 colors.
Of course this is nothing new, but it just really struck me because I've been working on a blog post about texture representation on modern consoles and it is crazy how complex it has gotten: texture tiles, block compression, non-linear texel ordering (e.g. Morton order), ...
I don't think someone used this approach in 1993. Textures were drawn by hand. But I think it's still fine to use such modern way of generating textures, since it may produce better-looking result.
I thought I could really level up with Claude and I started working on a boxing game. It's been a total disaster. .·°՞(˃ ᗜ ˂)՞°·.
Some details are a bit too cool for 1993, though, and assume high frame rate (won't work that well at low fps). Smooth weapon animations with a lot of frames, tiny per-pixel effects on bullet holes and flash sprites, smooth movement and object position calculations that use precise math instead of fast rough estimates resemble Chasm: The Rift or Quake (the concept of idle animations, e. g. objects moving in the starting view of difficulty selection room, assumes that there is some performance to waste on details that make the world less empty).
This is my complaint with a lot of "graphical enhancement" mods for games like Deus Ex.
Unless they touch everything, the inconsistent level of detail is worse than consistently low-res meshes/textures.
I suggest to use not only darker variants, but also brighter ones - for bright map areas and maybe for some lighting effects like flashlight.
I made a very similar project [0] in C 2 years ago, a chunked ray caster that could handle multiple height levels. Was one of my first C projects, pretty crappy but was fun.
Anyone have any ideas how to make it more memory efficient?
It’s full of bugs was just a for fun project
[0] - https://github.com/con-dog/chunked-z-level-raycaster/blob/ma...
The flight simulator / magic carpet easter egg in Microsoft Excel 97 used that same shaded-colormap palette trick, plus some dithering:
https://rezmason.github.io/excel_97_egg https://rezmason.github.io/excel_97_egg/about.html
I'm impressed by your sprite pipeline and gibs animations. Your attention to detail and navigation of constraints have really paid off, I can't wait to play this sometime
I did write a tool for generating the sprites from 3D models though[2]. It uses plain old OpenGL 1.1 to draw the sprite and grabs the framebuffer directly. It is drawn fullbright so i can paint the lighting directly on the sprite's texture (using a Krita plugin i wrote[3][4] - the model is something i threw together with Blender's default generated UV since i didn't care for the details).
I wonder if doing some sort of postprocessing (after rendering with with shading) like you do with your game would help with the finer details since i also found that rendering from 3D models to sprites creates very "mushy" results most of the time because of all the details getting lost. I notice the colors also become more saturated after postprocessing in your examples, is this after it finds the closest color in the palette or the result of the postprocess? I'd like to keep the overall hue+saturation of the model so maybe doing post-processing on a grayscale render to shade the shadows/dark areas but keep highlights as-is and then multiplying that with the fullbright image would produce results that wont shift the saturation.
[0] https://bad-sector.itch.io/post-apocalyptic-petra
[1] https://codeberg.org/badsector/PetraEngine/src/commit/14ca16...
[2] http://runtimeterror.com/pages/iv/images/95ddebc51e4dfa8a5af...
[3] http://runtimeterror.com/tools/kritaview3d/
[4] http://runtimeterror.com/pages/iv/images/535f0e09e590d8a1731...
It's the result of the Blender compositor postprocessing, just keep in mind it falls apart once you go low enough in resolution (it's an image space thing after all), so I'm not sure if that helps your case.
EDIT: Also, your project is very cool!
EDIT: Oh nevermind. I guess brightmaps are more flexible.
This is an extremely detailed article on every level and I can’t wait to deep dive into it. Marko really nailed the “old” look but it still looks fresh and new.
It's sad. That's why I never finished playing Wolfenstein 3D - it looks too boring. In the other hand I enjoy playing Doom, mods for it and games using its engine.
I hope the author can still add some improvements to allow such boring look typical for raycaster engines.
The author seems to consider open-sourcing the engine, I would also be interested in the mentioned scripts for asset creation. Those scripts would make a great toolset for asset creation in this style.
Inconsistent resolution isn't necessarily a bad thing, e.g. Elite for the BBC Micro changes video mode part way down the screen so it can display both high resolution monochrome wireframe 3D and a lower resolution color map/UI below, but it's not idiomatic to the MS-DOS style this game is going for.
(Nice job, seriously)
It doesn't look like slop at all, and it looks like it actually is. Could have been used to generate art assets, or finish something author did not have the energy to do before. Nobody cares if that was the case. Why the hate towards AI even?
what's unreasonable about this though?
The comments here are a cesspool unfortunately. People bickering about pronouns used for cats, how many shots it takes for a vase to explode, or whether or not some circa-1993 software was used or mentioned.
What I don't like is to see claims like "no AI slop"
And yet it's riddled with emdashes and language "by hand"
Seeing the skills of the writer, he definitely should be able to, but then I don't understand the claim.
> If this sounds unreasonable to you, that is because it is.
Those listed, are tame. I don't understand this kind of faux modesty.
> My goal was to build a complete, shippable first-person shooter using techniques that were common in the early 90s
Goes on to explain how they used 3D blender...which wasn't available until 1998.
A vanity cat project being tailored and submitted for nostalgia clickbait. I don't think there's anything useful to take away from this other than some color shade selection ideas.
In the early 90s, there was enough money in this kind of software that you could have hired a specialist 3D artist to use the software that was available at the time, e.g. LightWave 3D. When it's only a single-person project, I think it's reasonable to stick with what you know.
I think I'm gonna have to do it anyway, because some players claim they get nausea when playing at such low resolution (320x240), and the only way to give them higher resolutions that perform reasonably is to have it hardware accelerated.
Renderer is abstracted away already, but the real difference would probably be occlusion culling... With raycasting, I get it for free, but if I'd go down the hardware accelerated path I'd have to pick something more clever.
Raycasting and software rendering in general tends to scale poorly with resolution, even with vectorization and all the bells and whistles of modern CPUs.
As an example this[0] video shows the benchmark from Post Apocalyptic Petra running on my previous GPU (RX 5700 XT) which all it does is build a per-frame (client-side) vertex-buffer in OpenGL 1.1 (the engine was made for actual retro PCs running DOS and Win9x so it does some rudimentary occlusion culling but that mainly affects 90s hardware, not anything released since 2000 or so). If anything, the rendering has so little overhead that half of the framerate is "eaten" by the FPS counter overlay :-P.
[0] https://www.youtube.com/watch?v=64ysz5rXkzw
Thinking about modern games, a single character model probably has more vertices than my entire level (and yours probably), so it's definitely reasonable to expect occlusion culling for such simple geometry might actually reduce performance rather than increase it.
Meanwhile more current games have much higher polycounts, easily going above 100K triangles - e.g. Dante from DMC5, a ~7 year old game, apparently has ~190K triangles and that had to run on the more anemic PS4/XBone hardware :-P (though i'm not sure if it used the full 190K model there or some cut down version).
[0] http://runtimeterror.com/pages/iv/images/1073c7062db40837240...
But ignoring the GPU you have on your system is boring