New demo uploaded: Wolfenstein 3D - raycasting demo with textures

All aspects of programming on the Commander X16.
Post Reply
Jeffrey
Posts: 60
Joined: Fri Feb 19, 2021 9:46 am

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by Jeffrey »




Wolfenstein 3D - raycasting demo with textures




View File






Raycaster demo (written in c and assembly)

This version is a big improvement in performance: it now runs at 10+ fps! ?

I am quite happy with the speed. The demo plays quite nicely now.

See below description of version 1.3.0 for details.

---

This is a raycaster demo written in c and assembly for the Commander x16. I've been trying out the x16 and thought it would be a cool idea to start working on a raycaster.

Ultimately it would be great if "Wolfenstein 3D" can somehow be ported to the x16. That would be a BIG challenge though! ?

This is how it looks now:

raycasting_demo_1.3.0a.gif

Speed improvements in 1.3.0:

Now running at 10+ fps! ?

- Using zero page addresses for pretty much all my variables

- Using fast multipliers that use "square" tables: https://codebase64.org/doku.php?id=base:seriously_fast_multiplication

- Inlined the fast multipliers, so less copying of values, no jsr and rts

- Re-using the somewhat "static" parts of the multiplications, so it won't be re-loaded/calculate each ray (this was harder than it sounds, quite of bit of refactoring done)

    - Cosine and Sine fractions are player-related, and even though they are negated sometimes, they (that is their squares) could be reused for (almost) each ray

    - The (square of the) fraction of the tile the player is standing in -to be used for calculating the initial x/y interception for each ray- could be reused

- Cleaned up the main loop and several other parts

- Replaced the 16-bit slow divider with a 512-entry table: distance2height (major improvement!!) ?

 

New in this version 1.2.0:

- draw functions have been ported to assembly. Much faster!

- dda casting functions have been ported to assembly. Much faster!

- drawing textures!

- automatic generation of routine to draw ceiling and floor (only 4 cycles per plain pixel)

- automatic generation of around 512 routines for drawing textures (only 8 cycles per textures pixel)

- using joystick controls (you can use arrow keys and alt to control, you can hold down keys)

- a few textures from Wolfenstein 3D (shareware version) have been added (loaded at startup)

- changed the map to look like the first level in Wolfenstein 3D

- added a border around the render area, just like Wolfenstein 3D

Usage

Unpack the zip. Make sure you have the .BIN files in the same folder as the source files.

To compile: (this assumes cc65 is installed)

    cl65 -t cx16 -o RAY.PRG ray.c ray_asm.asm -O3

To run:

    x16emu.exe -prg RAY.PRG -run

To play:

    up - move forwards

    down - move backwards

    left - turn left

    right - turn right

    alt-left - strafe left

    alt-right - strafe right

To debug:

    p - turn on log screen

    o - turn off log screen

    t - turn on test ray

    l - rotate test ray left

    j - rotate test ray right

Known issues (1.2.0)

- Sometimes there is a corner of a wall not drawn correctly

- Since there is no real V-sync you get "shearing" in the screen (requires double buffering)

 Next up:

- Lots of speed improvements

- Lots of cleanup of code (its messy now)

- Add a time-per-frame indicator (using a vsync interrupt counter)

- Mooaarr wall-textures!

- Double buffer to prevent shearing

- Show a map on the screen

- Bigger map (limit is now 16x16)

- Opening doors

- Add (scaled) "sprites"

- Lamps (scaled) hanging from ceiling

- Stats in lower part, gun visible

- AI, enemies

Having fun! ?

Jeffrey






 
Ender
Posts: 220
Joined: Sat May 09, 2020 9:32 pm

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by Ender »


This is really cool! I'd really be curious how fast this can get.  Skimming the assembly CC65 generates, I see a lot of JSR's.  So much branching certainly would slow it down. It should be interesting to see how much faster it could be written directly in assembly.  Compiling with -O is noticeably faster as well.

As a fun sidenote, running this with the emulator in warp mode, it's practically a playable game ?

Jeffrey
Posts: 60
Joined: Fri Feb 19, 2021 9:46 am

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by Jeffrey »


I just uploaded a new version of the raycaster. Nice colors and quite a lot faster now:

raytracer.gif.995589ac2ec611a4b55800837fa65b31.gif

This is more fun than I had imagined. ?

Jeffrey
Posts: 60
Joined: Fri Feb 19, 2021 9:46 am

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by Jeffrey »


Trying to draw some textures:

textures_poc.png

This is just in PoC now. Its very slow. But I now know how to make it work in principle.

Now I somehow have to make this perform... ?

ZeroByte
Posts: 714
Joined: Wed Feb 10, 2021 2:40 pm

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by ZeroByte »


Have you heard of the YT channel "One Lone Coder?" His stuff is all in C++ using his own custom game engine, but he covers a lot of relevant topics and I've learned a lot watching them anyway. He did a video about a fast raycast algorithm which would fit this application. Here's a Link to the video. Not sure if you've already seen it or whether your code essentially does this already, but it might be useful for you.

Jeffrey
Posts: 60
Joined: Fri Feb 19, 2021 9:46 am

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by Jeffrey »



1 hour ago, ZeroByte said:




Have you heard of the YT channel "One Lone Coder?" His stuff is all in C++ using his own custom game engine, but he covers a lot of relevant topics and I've learned a lot watching them anyway. He did a video about a fast raycast algorithm which would fit this application. Here's a Link to the video. Not sure if you've already seen it or whether your code essentially does this already, but it might be useful for you.



Thanks! ?

Yes I already saw his video. In fact I am subscribed to his channel ?. He always creates very instructive videos about how to do things from scratch. He is an inspiration.

For this topic he refers to this blog: https://lodev.org/cgtutor/raycasting.html

That technique however uses a somewhat diffrerent technique than the original Wolfenstein did: the original technique is (I think, but I could be wrong) better suited if you only have 8-16 bit fixed point numbers (and not floating point numbers). 

Here is a video about the original Wolfenstein 3D technique that was very useful to me:





It's fascinating when diving into this stuff: how brilliant John Carmack was to figure this stuff out by himself in those days.

Regards,

Jeffrey 

PS. In order to speed up drawing (massively) I am now also generating "hardcoded" machine code for drawing each possible wall-height. Pretty crazy, but it really works well ?

User avatar
desertfish
Posts: 1094
Joined: Tue Aug 25, 2020 8:27 pm
Location: Netherlands

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by desertfish »



37 minutes ago, Jeffrey said:




generating "hardcoded" machine code for drawing each possible wall-height.



I'm fairly sure the original wolfenstein did the same thing.  (or maybe Doom did) ?

ZeroByte
Posts: 714
Joined: Wed Feb 10, 2021 2:40 pm

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by ZeroByte »


 


1 hour ago, desertfish said:




I'm fairly sure the original wolfenstein did the same thing.  (or maybe Doom did) ?



Probably Wolf3d. Doom's render used multiple passes for its render. I found a video once that showed the render in slow-motion so you could sit there and watch it draw the frame.


2 hours ago, Jeffrey said:




PS. In order to speed up drawing (massively) I am now also generating "hardcoded" machine code for drawing each possible wall-height. Pretty crazy, but it really works well ?



Hey, whatever it takes to get it to run - I'm really impressed with the progress thus far, man!

I've personally been pondering what I would do if I wanted to port Wolf3d to the X16 - and I'm thinking a speed optimization would be to cut the resolution in half and then use the VERA scaling to scale it back up to full screen, or maybe even 1/4 res upscaled 4x.... i.e. only draw in the upper-left 1/4 or 1/8 of the video memory area.

You could then use a raster IRQ to set VERA back to 1:1 scaling when it reaches the top row of the HUD, and render the HUD on layer1 using tiles.

Jeffrey
Posts: 60
Joined: Fri Feb 19, 2021 9:46 am

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by Jeffrey »



9 hours ago, desertfish said:




I'm fairly sure the original wolfenstein did the same thing.  (or maybe Doom did) ?



Indeed. Thats where I got the idea from. ?

image.png.27361eed05179f0bc8511e4cd6b987b4.png

The above mentioned video says: "As there is only a finite number of possible heights, Wolfenstein code generates one routine for every possible height".

Right now I store the textures in VRAM. When I generate such a routine its simply looks something like this:


Quote




LDA VERA_DATA1



STA VERA_DATA0



STA VERA_DATA0



LDA VERA_DATA1



STA VERA_DATA0



LDA VERA_DATA1



STA VERA_DATA0



STA VERA_DATA0



...



In that example it writes about 2-3 times more to the screen than it reads from the texture (which is 64x64 pixels). The nice thing about VERA is that you can do this vertically, which suits drawing columns for each ray very well.

This takes less than 8 cycles per pixel. Sometimes you read more than you write (when walls are smaller than the textures). Sometimes you write more than you read (when the walls are taller than the texture). All in all a little less than 8 cycles. I still need to optimize the smaller walls (as they dummy-load too much right now, so I probably need a secondary, smaller texture or double my stride).

For the ceiling and floor I simply have a  single routine with a whole bunch to STA VERA_DATA0's and I jump in that routine at exactly the right place (with the correct color in A). So those take only 4 cycles per pixel.

I can still speed that up a little by remembering how tall the wall (on that column) was the previous frame, so I only have to remove that old wall  and not redraw the entire ceiling or floor.

Fun stuff! ? 

 

Jeffrey
Posts: 60
Joined: Fri Feb 19, 2021 9:46 am

New demo uploaded: Wolfenstein 3D - raycasting demo with textures

Post by Jeffrey »



7 hours ago, ZeroByte said:




Hey, whatever it takes to get it to run - I'm really impressed with the progress thus far, man!



I've personally been pondering what I would do if I wanted to port Wolf3d to the X16 - and I'm thinking a speed optimization would be to cut the resolution in half and then use the VERA scaling to scale it back up to full screen, or maybe even 1/4 res upscaled 4x.... i.e. only draw in the upper-left 1/4 or 1/8 of the video memory area.



You could then use a raster IRQ to set VERA back to 1:1 scaling when it reaches the top row of the HUD, and render the HUD on layer1 using tiles.



Thanks. Its a lot of fun doing it! ?

Yeah. Right now I estimate that a speed of 10-15 fps is achievable with a resolution of 304x152 pixels for the 3D-rendering part, which is the resolution the original Wolfenstein 3D shareware version had (the NTSC version). The PAL version has vertical 182 pixels.

When you want more than 15 fps the most effective way to do that (I think) would be to scale in width: making the vertical bars look like 4 pixels wide (instead of 1). It's only a quarter of the work and would likely do the trick (achieving 50-60 fps). And might still be nice to look at. The sprites might look weird though. Not sure.

Currently I am handwriting the ray-casting routines (DDA) in assembly. Quite hard and time consuming. Because that is now the bottleneck. If that works we'll see what kind of speed comes out of that.

Of course all of the above does not factor in the game itself, just the engine. So it will probably be a bit slower. But the goal of this demo is to see if a raycasting engine is achievable at reasonable speeds on the X16.

Having fun just thinking about this problem! ?

PS. earlier I was thinking of using 100+ sprites and showing them multiple times in a single frame (like I did in the vertical bar scroller) which would effectively create around 500 sprites on screen and then placing those sprites very carefully on the screen so 4 of them (stacked vertically) would effectively create a verticall bar (with a texture) that would represent a cast ray and would be 3 or 4 pixels wide. That would me much faster (than blitting to the screen), but I've abandoned that idea because it doesn't seem to work with multiple textures.

Post Reply