Raycasting (wolf3D-style) engine demo + API musings

raycaster.zip (19.2 KB)

Hello! I ported some code over to learn the C API. The engine is extremely barebones, but I’ll post the code after a little more work if there’s interest. Lua calls a draw function which writes directly to the framebuffer, then from lua I add the FPS counter and text. Note that I don’t have a device yet.

raycastdemo4

I wrote up two backends: One a near direct port from the lodev tutorial (swapping doubles for floats) (https://lodev.org/cgtutor/raycasting.html) and the other is a port of … my port of lodev to use fixed point math functions (with some visual glitches not ironed out yet). Some folks in Discord tried it (thanks!) and show 30+ fps for both engines, with a ~10ish fps bump from fixed point.

My thought was to parameterize it a bit and maybe use it as part of a game engine library. Currently thinking about how to integrate it a bit better with the PD API.

Some development thoughts:

  • Textures are 1-bit (though … currently actually 8-bit), loaded sideways so texture spans can be read linearly to improve draw speed. I’m a bit worried about using LCDBitmaps to replace them. Putting the textures in a bitmaptable and letting Lua manage them would be great. It looks like I would lose performance since in the C side. I would have to hit getBitmapData() data at the start of each frame for every texture (or cache it for textures accessed). It’s also not clear how to use the “data” part retrurned (yet? maybe next SDK documents it? :slight_smile: ).
  • I could just internally allocate and manage some LCDBitmaps, perhaps? Then the engine could handle flipping the bit orientation when textures are loaded to make it easier on the user.
  • Integrating Sprites seems a bit tricky but possible… Looks like I would just want setSpriteDrawFunction(), except it could use a UserData *ptr or else I’d need globals to check my z-buffer during draw? Or maybe that’s not enough. I’d need its x/y to translate to screen space + maybe do other work. Might be better to reuse LCDBitmaps but have own spriting system, which sucks since I just need fast scaling and clipping with transparency.
  • Should be enough CPU headroom for floor/ceiling casting?
  • Easy to parameterize where to draw in the framebuffer and how big. Then you get status bars/etc.

Performance wise:

  • I could juice this more but need to get into the nitty gritty of the CPU more. I don’t know how the L1 cache is configured (if it works?), cachelines, SDRAM read-ahead, etc and if that’s good enough for drawing spans quickly. I imagine accessing the SDRAM can lose a lot of cycles.
  • No idea how to analyze performance with hardware-specific code :slight_smile:
  • Is there any scratch space available via the CPU’s built-in SRAM? Where’s the stack stored?
  • I care because A) more headroom means more special effects/sprites/etc! and B) don’t need to re-draw if nothing changes, so the faster it can draw the better battery life it’ll get.

Utility wise:

  • Easy to keep all the game logic / asset management in Lua. Nice!
  • A BSP-tree with a doom style wall renderer and/or quake style renderer (BSP + potentially visible set) could actually be faster than this for reasonably complex levels. It should also look better since you get angles/stairs. Raycasters aren’tt he best here.
  • However BSP levels are hard to modify at runtime. Portal based engines are easier to modify but slower.
  • With a raycaster you can change/shift the level inbetween frames.
  • Doesn’t have to be a FPS/action game!
  • Portals aren’t too big of a hack.
  • Sky and variable wall-heights aren’t too hard.
  • Texture animations (though these are never that hard).
  • Can use tricks to swap the map out entirely at transitions to create illusion of much larger maps.
  • Various tricks to allow lots of sprites/objects based on zones/visibility tests.

Not sure if I’ll continue this but folks might find some of the tidbits interesting.

11 Likes