Another World (Out of this World) port for the CX16
Posted: Fri Aug 09, 2024 2:33 am
Some of you may have seen my other posts about my attempts to port the game "Another World" from the Amiga to the commander X16. I'll use this thread to keep you all updated on my progress.
What started out as a learning exercise soon became a full on project. I originally coded it in C using CC65, but found that it ran very slow.
I scrapped my C code and taught myself 65c02 assembly, and re-wrote the entire thing in pure assembly. Along the way I have learned a lot about the 65c02, the CX16, the Kernal, and the VERA.
The game is rendered using 2d polygonal vector graphics. The file formats are quite unique, you can tell that it was designed by one person with little outside influence. One of the awesome things was that the polygons are defined in a way that suits the polygon fill helper in the VERA perfectly.
Using the VERA FX Polygon Fill Helper
I set out to write a filling algorithm using the VERA FX. One of the most challenging things about this port is the fact that the Amiga is a 16-bit computer, and the CX16 only 8. The 320 pixel width has caused me so many headaches. Writing a signed 24-bit division routine for the polygon fill helper wasn't fun either(you need it for slope calcs). I had to learn a lot about how division and multiplication works on an 8-bit computer. Anyway, I finally got it working, but it turns out that the game code uses a lot of dodgy "hacks" to clip or not clip pixels. So you need to emulate that perfectly or else your polygons don't display correctly (or at all). The polygon fill helper is somewhat rigid in its requirements, so for things like clipping and overflowing it gets very complicated fast. I got it about 75% working, but it wasn't acceptable so I took a different approach.
Alternative polygon filling
It turns out the Commander X16 is pretty fast anyway. I wrote scanline table filler. I'm not sure if it has a name, it's my own design. The polygons in the game are all fortunately limited to 256x256 in size (they are scaled later), so I keep a left and a right side table and using bresenham I "draw" lines between vertices in for each side of the polygon. Then using those tables, I scan down them one line at a time and draw filled horizontal lines between the sides. It results in a perfect replica of the original polygon.
My horizontal line algorithm uses the 32-bit cache writes of the VERA FX. The polygon routines I have now are about 90% correct. There still seems to be a couple of edge cases where a polygon isn't drawn, or it overflows to the next line.
Here is a real-time gif of the game intro: Game Speed
The original game actually ran at 50hz. I was hoping to get at least 20fps for the game, but to my surprise my code was fast enough to match the original speed, in fact it can run faster! At the moment I haven't implemented any interrupts I am using the kernal default, which is 60hz, but it still looks great.
I was so worried about speed that I decided to make my screen resolution 256x192. However since the speed is so good I'm going to go to 320x192. I will have to update all the X values to 16-bit which is painful.
VRAM
Why 320x192 and not the original 320x200? Well this is because of the way the VERA addresses the VRAM in blocks of 2048 bytes. If I went to the next block, it would have to be 320x204. If I used that resolution, I wouldn't have enough VRAM for the (triple) buffering the game uses. That said I may revisit this scenario, I might be able to make it work, albeit with a 4 pixel black bar at the bottom of the screen, and I'd have to sacrifice the text mode font. Other system implementations (eg MS-DOS) use a screen buffer for display, but because of the way the VERA handles page switching, I don't need that and have devised a way to rid the game of slow screen copies every frame (not completely unavoidable, but a whole page less every frame). You can see more about how the screen buffering works on this breakdown: https://fabiensanglard.net/another_worl ... index.html.
Next Steps
I've got about 80% of the game engine opcodes working. I have rudimentary keyboard support. The main thing I'm aiming for is to get it to play the entire introduction and first level without any problems. At the moment, the intro finishes flaky, and the first level doesn't load. That said, it's likely something small. The game runs entirely on a virtual machine so if most of those things work then the rest will too. I'm currently working on changing the screen res from 256 to 320. The fact that everything is 16-bit is very draining.
Previously I also have said sound isn't possible, but I may have worked out a way to do it. The main limitation is the 512kb of ram. But since loading from the SD card is almost as fast as loading from memory I might be able to stream sound from the disk instead of memory. Alternatively, I could just make it a "feature" if you have 2mb of RAM. It would also depend if it could be done fast enough but I'm confident it could be. Also I've extracted all the resources manually, I need to implement that in the game.
Still to do really are:
- Get game going at original screen res 320x200
- Fix any broken implementations of opcodes
- Finish keyboard input and implement gamepad input
- Text rendering (should I use default font?)
- Implementation of resource decompression
- Sound
- Optimisations (there are heaps)
- Full playthrough testing
I've been toying with the idea of making a few videos on my work for youtube. I'm not a youtuber or anything but I know it would be something I'd watch haha. There's heaps I haven't mentioned here. I've written several debugging tools, disassemblers for the game, resource extractors, and other stuff. Let me know if you'd be interested.
What started out as a learning exercise soon became a full on project. I originally coded it in C using CC65, but found that it ran very slow.
I scrapped my C code and taught myself 65c02 assembly, and re-wrote the entire thing in pure assembly. Along the way I have learned a lot about the 65c02, the CX16, the Kernal, and the VERA.
The game is rendered using 2d polygonal vector graphics. The file formats are quite unique, you can tell that it was designed by one person with little outside influence. One of the awesome things was that the polygons are defined in a way that suits the polygon fill helper in the VERA perfectly.
Using the VERA FX Polygon Fill Helper
I set out to write a filling algorithm using the VERA FX. One of the most challenging things about this port is the fact that the Amiga is a 16-bit computer, and the CX16 only 8. The 320 pixel width has caused me so many headaches. Writing a signed 24-bit division routine for the polygon fill helper wasn't fun either(you need it for slope calcs). I had to learn a lot about how division and multiplication works on an 8-bit computer. Anyway, I finally got it working, but it turns out that the game code uses a lot of dodgy "hacks" to clip or not clip pixels. So you need to emulate that perfectly or else your polygons don't display correctly (or at all). The polygon fill helper is somewhat rigid in its requirements, so for things like clipping and overflowing it gets very complicated fast. I got it about 75% working, but it wasn't acceptable so I took a different approach.
Alternative polygon filling
It turns out the Commander X16 is pretty fast anyway. I wrote scanline table filler. I'm not sure if it has a name, it's my own design. The polygons in the game are all fortunately limited to 256x256 in size (they are scaled later), so I keep a left and a right side table and using bresenham I "draw" lines between vertices in for each side of the polygon. Then using those tables, I scan down them one line at a time and draw filled horizontal lines between the sides. It results in a perfect replica of the original polygon.
My horizontal line algorithm uses the 32-bit cache writes of the VERA FX. The polygon routines I have now are about 90% correct. There still seems to be a couple of edge cases where a polygon isn't drawn, or it overflows to the next line.
Here is a real-time gif of the game intro: Game Speed
The original game actually ran at 50hz. I was hoping to get at least 20fps for the game, but to my surprise my code was fast enough to match the original speed, in fact it can run faster! At the moment I haven't implemented any interrupts I am using the kernal default, which is 60hz, but it still looks great.
I was so worried about speed that I decided to make my screen resolution 256x192. However since the speed is so good I'm going to go to 320x192. I will have to update all the X values to 16-bit which is painful.
VRAM
Why 320x192 and not the original 320x200? Well this is because of the way the VERA addresses the VRAM in blocks of 2048 bytes. If I went to the next block, it would have to be 320x204. If I used that resolution, I wouldn't have enough VRAM for the (triple) buffering the game uses. That said I may revisit this scenario, I might be able to make it work, albeit with a 4 pixel black bar at the bottom of the screen, and I'd have to sacrifice the text mode font. Other system implementations (eg MS-DOS) use a screen buffer for display, but because of the way the VERA handles page switching, I don't need that and have devised a way to rid the game of slow screen copies every frame (not completely unavoidable, but a whole page less every frame). You can see more about how the screen buffering works on this breakdown: https://fabiensanglard.net/another_worl ... index.html.
Next Steps
I've got about 80% of the game engine opcodes working. I have rudimentary keyboard support. The main thing I'm aiming for is to get it to play the entire introduction and first level without any problems. At the moment, the intro finishes flaky, and the first level doesn't load. That said, it's likely something small. The game runs entirely on a virtual machine so if most of those things work then the rest will too. I'm currently working on changing the screen res from 256 to 320. The fact that everything is 16-bit is very draining.
Previously I also have said sound isn't possible, but I may have worked out a way to do it. The main limitation is the 512kb of ram. But since loading from the SD card is almost as fast as loading from memory I might be able to stream sound from the disk instead of memory. Alternatively, I could just make it a "feature" if you have 2mb of RAM. It would also depend if it could be done fast enough but I'm confident it could be. Also I've extracted all the resources manually, I need to implement that in the game.
Still to do really are:
- Get game going at original screen res 320x200
- Fix any broken implementations of opcodes
- Finish keyboard input and implement gamepad input
- Text rendering (should I use default font?)
- Implementation of resource decompression
- Sound
- Optimisations (there are heaps)
- Full playthrough testing
I've been toying with the idea of making a few videos on my work for youtube. I'm not a youtuber or anything but I know it would be something I'd watch haha. There's heaps I haven't mentioned here. I've written several debugging tools, disassemblers for the game, resource extractors, and other stuff. Let me know if you'd be interested.