Cooking Circle

RSS

The Wolfenstein 3D challenge

Something for the future… Years ago when I used my SAM every day (and my PC was barely capable of running an emulator) I experimented with a raycasting 3D displayer, on a single texture-mapped wall.  I thought it was great, but unfortunately lost the disk.

WAS IT AS GREAT AS I REMEMBER?  I came across this on Youtube just now, and it’s about what I was aiming for.

It wasn’t as smooth and finished as this, but about the same resolution.  My version was filled in (this link only prints every other line I think, and is, therefore, nice and smooth), but we’re nearly there.

Should this be my next challenge?  This stuff’s been plaguing me for years, even though I know it’s largely irrelevant these days.  Shadows of the same questions keep popping up at work, such as - How long should it take to save a 30mb file to our Citrix environment?  How much bandwidth is reasonable per user?  If Windows needs over 10 seconds to perform an action, is doing Application.ScreenUpdating=false really effective (especially as it looks so ghastly)?

With the SAM I’ve long thought of it in quite simple terms.  Thinking about whether I catch up with or step over the scanline while I’m drawing the frame, is frankly too much like hard work for me.  But it’s not *so* slow, drawing to mode 4.  A screen is 24576 bytes long, which can be filled with solid colour with the stack pointer in 12288 PUSHes.  At 11 TStates per instruction and 78000 TStates a frame, it takes 2 frames just to clear the screen.  With speeds like that, running at 12.5 frames per second is the norm, even for a standard bitmap-based update.

So why would you feel like a failure if your 3D game didn’t run @50fps??!

My technique wasn’t finished but worked on 64 vertical strips of 4 pixels each, and were printed from a bunch of dedicated ‘magnifiy print’ routines, mostly containing this sort of rolled-out loop:

ld a,(hl)

ld (de),a

inc d

ld a,(hl)

ld (de),a

inc d

inc h

ld a,(hl)

ld (de),a

etc…  At the bottom I would set 7,l; set 7,e and traverse back up, filling in the blanks.  The scaling was all precalculated, and I even considered making a specialised routine for each bit of wall, at each size I wanted it.  Yes, it would be large, but it could be compiled before each level was played.

So the inner loop was about 22 Tstates for 4 pixels, which means 270336 TStates total, or 3.5 frames of print work, and a healthy 36000 TStates left for admin.  I think I was running at 12.5 frames per update…  Doesn’t look so bad to me, right?  If I took the Doom route and put in a HUD in the bottom this would be actually feasible.

Now, add to that a few little tricks I’ve picked up from coding some demos.  Here’s one big one:  Instead of drawing every frame, only draw every other frame, and interlace the results over your previous frame.  You may have seen this in Spectrum demos and thought it too blurry.  Well, at 12.5 fps full screen, this turns into 25fps ‘interlaced’.  And if you are clever with palette changes, you can get each old frame to have half intensity and effectively sharpen up your images.

It won’t look perfect, but at a steady 25fps and motion picture blur aliased to grey on each doubled frame, I think we’re getting there!

So… Should this be my next challenge?  Now that I know I can finish games off, maybe I could start stretching myself…  just a thought.  Demo coming soon, methinks.