Each time I return to a platform there's the ramp-up time where I re-learn what I knew before. And Knight Lore on the Coco3 is no different. It has been a few years since Lode Runner after all... but then I also find I learn something new as well.
Today's exercise was getting 20KB of data loaded into memory from disk, preferably independently of the main executable - something I did for Lode Runner. In the end it's almost trivial, but when you can't recall how to do it, and then you encounter some corruption along the way, it chews up your spare time. In the end it was all resolved and I learned something new about the Coco3.
The data - location and graphics data in this case - resides in a single .ASM file generated by a custom utility from a memory dump of Knight Lore running in MESS. The same utility I used to generate all the C data structures and arrays. This .ASM file is then .included in a very small file which is then built and LOADM'd from BASIC before loading and running the main executable.
For the curious, here's that file
.include "coco3.asm"
; $2000,$4000,$6000
.org MMUTSK1+1
.db DATA_PG1, DATA_PG2, DATA_PG3
.org 0x2000
.include "kl_dat.asm"
; $2000,$4000,$6000
.org MMUTSK1+1
.db 0x39, 0x3a, 0x3b
This loads directly into the GIME's MMU registers on-the-fly, allowing the data to be loaded into pages of 128KB memory not mapped by default. And lastly it restores the default page mapping. It doesn't even have to be executed, simply loading it does the trick. When the main executable runs, it simply re-maps the pages into memory and the data magically appears.
This blog chronicles my progress porting various retro games to other retro platforms. The goal in each project - at least when targeting a new CPU - is to effectively replicate the original graphics and the original code line-by-line, to produce a 100% accurate port of the original game.
Pages
▼
Friday, 26 February 2016
Thursday, 25 February 2016
Turning the first sod on the Coco3
In preparation for my work trip, more than anything else, I decided to set up the toolchain and a template project for the Coco3 port of Knight Lore.
I started with my Coco3 initialisation code from Lode Runner (most recently used to display the ZX Spectrum Knight Lore, Alien 8 and Pentagram title screens on the Coco3), and added all the labelled addresses and routines from the original disassembly, with appropriate RTS/BRA instructions added for the most part. I then simply copied-and-pasted the variables from the Z80 listing - a benefit of using the same assembler family. The result is a 6809 .ASM file that contains all the variables and stub routines of the original, and assembles and runs.
I couldn't stop there of course and started coding the initialisation and main routines, including the main menu display and requisite font display routines.
Now I only have to flesh out a few routines and it's all done - right!?!
Of course the challenge of translating Z80 to 6809 is already at the forefront of the process, and it's fair to say that the code thus far - in stark contrast to the Lode Runner port - bares little resemblance to the Z80 original. I suspect that will be par for the course on this project, and will no doubt bolster my 6809 coding skills. I just hope I don't get to the end of the port wanting to re-write the first half!
Unfortunately there's a significant amount of coding to be done before anything else gets displayed. However I do now know which routines are crucial in getting the correct display, and which ones can be omitted for the purposes of seeing something.
I started with my Coco3 initialisation code from Lode Runner (most recently used to display the ZX Spectrum Knight Lore, Alien 8 and Pentagram title screens on the Coco3), and added all the labelled addresses and routines from the original disassembly, with appropriate RTS/BRA instructions added for the most part. I then simply copied-and-pasted the variables from the Z80 listing - a benefit of using the same assembler family. The result is a 6809 .ASM file that contains all the variables and stub routines of the original, and assembles and runs.
I couldn't stop there of course and started coding the initialisation and main routines, including the main menu display and requisite font display routines.
Knight Lore for the Coco 3 - Main Menu |
Now I only have to flesh out a few routines and it's all done - right!?!
Of course the challenge of translating Z80 to 6809 is already at the forefront of the process, and it's fair to say that the code thus far - in stark contrast to the Lode Runner port - bares little resemblance to the Z80 original. I suspect that will be par for the course on this project, and will no doubt bolster my 6809 coding skills. I just hope I don't get to the end of the port wanting to re-write the first half!
Unfortunately there's a significant amount of coding to be done before anything else gets displayed. However I do now know which routines are crucial in getting the correct display, and which ones can be omitted for the purposes of seeing something.
Wednesday, 24 February 2016
More bugs and back to the Amiga
I've completed the pickup/drop hardware sprite logic and so Neo Geo is now on par with the other ports, except for the Z-order issue.
In the process of testing I found another bug in my Knight Lore core C implementation; dropping objects sometimes causes those objects to disappear. I've added this to the to-fix list along with a couple of other bugs I've seen infrequently; one room always kills you when you first walk into it and walking into a room from a raised arch will leave you suspended in mid-air.
But for now I'm going to return to the Amiga port and get CPC graphics working. Once that's complete I should only have the above-mentioned core issues to resolve, which will of course affect all ports. I've spent far too long on this aspect of the project and really want to put the C ports to bed - make the ports playable and release the source before moving on to the original goal of this whole project!
This weekend I'm off the the US again for two weeks for work. That's another two weeks of lonely nights in a hotel room, and although last trip I didn't get much done on the project, the novelty of it all has definitely worn off and I'll make a concerted effort this time 'round.
To this end I'll be making sure my laptop has all the Coco 3 technical documentation, development toolchains and emulation environments that I'll need for the rather daunting task that lays ahead. I still don't have a feel for how I'll mirror the heavy use of the Z80 IX & IY registers on the 6809, but I'm sure I'll work out something.
Phase one will be glorious monochrome, to get an idea of how the 1.89MHz 6809 is going to handle what was being done by a 3.5MHz Z80. I'm sure it'll compare favourably, especially given the fact that the Coco 3 doesn't have the issue of video memory contention like the ZX Spectrum. Hopefully there's enough headroom for a more colourful version down the track!?! If not, it's not going to be any worse than the BBC Micro port! ;)
UPDATE: CPC graphics on the Amiga. Not as painful as I first feared. Funnily enough I had exactly the same bug as the Neo Geo port, in that the orange rooms were actually red. Of course I couldn't for the life of me recall what the issue was for at least 5 minutes - then it came to me.
Still a few palette issues to sort as the palette must be programmed on-the-fly, unlike the PC and Neo Geo ports. However I'll likely back-port the Amiga palette changes to the PC as most retro ports won't be in 256-colour mode.
UPDATE#2: Fixed the remaining palette issues on the Amiga. The border colour for the main menu and game over message screens will never be correct when running CPC graphics, as the CPC sprite routines only support 4 colours. Not exactly a deal-breaker...
In the process of testing I found another bug in my Knight Lore core C implementation; dropping objects sometimes causes those objects to disappear. I've added this to the to-fix list along with a couple of other bugs I've seen infrequently; one room always kills you when you first walk into it and walking into a room from a raised arch will leave you suspended in mid-air.
But for now I'm going to return to the Amiga port and get CPC graphics working. Once that's complete I should only have the above-mentioned core issues to resolve, which will of course affect all ports. I've spent far too long on this aspect of the project and really want to put the C ports to bed - make the ports playable and release the source before moving on to the original goal of this whole project!
This weekend I'm off the the US again for two weeks for work. That's another two weeks of lonely nights in a hotel room, and although last trip I didn't get much done on the project, the novelty of it all has definitely worn off and I'll make a concerted effort this time 'round.
To this end I'll be making sure my laptop has all the Coco 3 technical documentation, development toolchains and emulation environments that I'll need for the rather daunting task that lays ahead. I still don't have a feel for how I'll mirror the heavy use of the Z80 IX & IY registers on the 6809, but I'm sure I'll work out something.
Phase one will be glorious monochrome, to get an idea of how the 1.89MHz 6809 is going to handle what was being done by a 3.5MHz Z80. I'm sure it'll compare favourably, especially given the fact that the Coco 3 doesn't have the issue of video memory contention like the ZX Spectrum. Hopefully there's enough headroom for a more colourful version down the track!?! If not, it's not going to be any worse than the BBC Micro port! ;)
UPDATE: CPC graphics on the Amiga. Not as painful as I first feared. Funnily enough I had exactly the same bug as the Neo Geo port, in that the orange rooms were actually red. Of course I couldn't for the life of me recall what the issue was for at least 5 minutes - then it came to me.
CPC graphics mode on the Amiga |
Still a few palette issues to sort as the palette must be programmed on-the-fly, unlike the PC and Neo Geo ports. However I'll likely back-port the Amiga palette changes to the PC as most retro ports won't be in 256-colour mode.
UPDATE#2: Fixed the remaining palette issues on the Amiga. The border colour for the main menu and game over message screens will never be correct when running CPC graphics, as the CPC sprite routines only support 4 colours. Not exactly a deal-breaker...
Tuesday, 23 February 2016
Getting the colours right
Again, Real Life has been putting a serious dent into my spare time but at lunchtime today I finally managed to get the palette right on the Neo Geo for both ZX Spectrum and CPC graphics modes.
It's actually been quite tricky and I've gone back to the drawing board several times in several areas over the last week or so. In fact I've had to regenerate all the tiles (sprites) and FIX layer graphics, including the panel - some several times over - as I've juggled the palette.
The panel is now generated from the CPC graphics, which includes a larger mask around the frame so that the sun/moon don't show either end without further trickery.
The challenge has not been only supporting both ZX Spectrum and CPC colours, but supporting them both at the same time, since the main menu and end-of-game screens are all from the ZX version, with ZX palette - that's half the FIX layer palette gone!
And a fact that didn't click earlier when it should've - the CPC graphics support 4 colours plus transparency, in 2 bits. And here is where the mystery extra byte in the sprite data comes into play! The CPC sprite rendering routine is a mess of lookup tables and self-modifying code, but what I've managed to deduce is that the 3rd byte is a flag that denotes colour 1 should actually be rendered as colour 3, which is otherwise used as the mask colour and normally rendered black. So on the Neo Geo, I've had to duplicate and modify the palette for these sprites.
And as I sit here typing this up, I've just realised there could be a better way to do it on the Neo Geo... oh well, I'm not changing it now.
The idea was always to keep code that differentiated between ZX and CPC graphics to a minimum to keep the code tidy and easy to maintain; I've been fairly successful by keeping the palettes somewhat compatible.
And just because I think this blog needs more eye candy...
And I think I will add the CPC title screen, as ordinary as it is, just as a visual indication of which version you're about to play!
UPDATE: And now I have...
That's it for the Neo Geo version; just need to go back and fix the game play issues related to having no .data segment (should be tedious but trivial) and of course the sprite Z-ordering.
UPDATE #2: Neo Geo now copies what would be in the .data segment into RAM - as a result it now has special objects that can be picked-up and dropped. I still need to add hardware sprite handling logic to this aspect of it, but game play is almost on par with the other ports now.
One of 4 room palettes of the CPC graphics mode (Neo Geo) |
It's actually been quite tricky and I've gone back to the drawing board several times in several areas over the last week or so. In fact I've had to regenerate all the tiles (sprites) and FIX layer graphics, including the panel - some several times over - as I've juggled the palette.
The panel is now generated from the CPC graphics, which includes a larger mask around the frame so that the sun/moon don't show either end without further trickery.
The challenge has not been only supporting both ZX Spectrum and CPC colours, but supporting them both at the same time, since the main menu and end-of-game screens are all from the ZX version, with ZX palette - that's half the FIX layer palette gone!
And a fact that didn't click earlier when it should've - the CPC graphics support 4 colours plus transparency, in 2 bits. And here is where the mystery extra byte in the sprite data comes into play! The CPC sprite rendering routine is a mess of lookup tables and self-modifying code, but what I've managed to deduce is that the 3rd byte is a flag that denotes colour 1 should actually be rendered as colour 3, which is otherwise used as the mask colour and normally rendered black. So on the Neo Geo, I've had to duplicate and modify the palette for these sprites.
And as I sit here typing this up, I've just realised there could be a better way to do it on the Neo Geo... oh well, I'm not changing it now.
The idea was always to keep code that differentiated between ZX and CPC graphics to a minimum to keep the code tidy and easy to maintain; I've been fairly successful by keeping the palettes somewhat compatible.
And just because I think this blog needs more eye candy...
The CPC orange theme. Because of a bug I didn't get to see this for some time |
And I think I will add the CPC title screen, as ordinary as it is, just as a visual indication of which version you're about to play!
UPDATE: And now I have...
The CPC title screen on the Neo Geo |
That's it for the Neo Geo version; just need to go back and fix the game play issues related to having no .data segment (should be tedious but trivial) and of course the sprite Z-ordering.
UPDATE #2: Neo Geo now copies what would be in the .data segment into RAM - as a result it now has special objects that can be picked-up and dropped. I still need to add hardware sprite handling logic to this aspect of it, but game play is almost on par with the other ports now.
Saturday, 20 February 2016
CPC on the Neo Geo
Real Life has been preventing me from doing much on Knight Lore over the last few days but today I managed to get the CPC graphics converted across to the Neo Geo and also set up the palette.
I still need to tweak the palette for the panel display, which is a juggling exercise on the FIX layer palette, but it's almost there. In the above, of the panel portion of the display, only the scrolls are the correct colour.
Looking pretty nice... just need to update the Amiga port for CPC graphics rendering.
CPC graphics on the Neo Geo |
I still need to tweak the palette for the panel display, which is a juggling exercise on the FIX layer palette, but it's almost there. In the above, of the panel portion of the display, only the scrolls are the correct colour.
Looking pretty nice... just need to update the Amiga port for CPC graphics rendering.
Wednesday, 17 February 2016
Not spritely enough!
This morning I started preparation on the Neo Geo port to support CPC graphics. Whilst enhancing my graphics conversion tool for the Neo Geo, I realised that I'd run out of sprites on the cartridge!
To develop/run a Neo Geo game under MAME, you need to hijack an existing game. That involves taking the original cartridge ROM images for a specific game, replacing select files (68K program code, sprites and FIX layer graphics) with your own content, and running under the original name.
The project template I originally used for my Donkey Kong port (WIP) and subsequently for Lode Runner and now Knight Lore was based on the Puzzle De Pon cartridge (GUID 202). With a single pair of sprite ROM images, that's sufficient for 16,384 sprite tiles. Given that the ZX version of Knight Lore has 12,032 you can see how I need more space to support the CPC graphics.
Looking through the MAME driver source code for the 'minimal' cartridge with twice the sprite ROM image size, I discovered a handful of candidates. The extra criteria was no fancy bank switching or protection schemes on the cartridge. Fortunately the first candidate, Legend Of Success Joe (GUID 029), fit the bill. I've simply chosen to ignore the fact that this cartridge is notorious for being arguably the worst game ever released on the Neo Geo.
In the process of switching the 'host' cartridge, I took the opportunity to clean up the makefile and reorganise ROM files in the development hierarchy. The only other gotcha was that the eye-catcher sprite bank for LOSJ was at $6F, residing in the 2nd pair of sprite files, which required tweaking in my conversion tool. But as of tonight, selecting legendos on MAME runs Knight Lore!
Tomorrow I'll hopefully complete the CPC graphics conversion.
To develop/run a Neo Geo game under MAME, you need to hijack an existing game. That involves taking the original cartridge ROM images for a specific game, replacing select files (68K program code, sprites and FIX layer graphics) with your own content, and running under the original name.
The project template I originally used for my Donkey Kong port (WIP) and subsequently for Lode Runner and now Knight Lore was based on the Puzzle De Pon cartridge (GUID 202). With a single pair of sprite ROM images, that's sufficient for 16,384 sprite tiles. Given that the ZX version of Knight Lore has 12,032 you can see how I need more space to support the CPC graphics.
Looking through the MAME driver source code for the 'minimal' cartridge with twice the sprite ROM image size, I discovered a handful of candidates. The extra criteria was no fancy bank switching or protection schemes on the cartridge. Fortunately the first candidate, Legend Of Success Joe (GUID 029), fit the bill. I've simply chosen to ignore the fact that this cartridge is notorious for being arguably the worst game ever released on the Neo Geo.
In the process of switching the 'host' cartridge, I took the opportunity to clean up the makefile and reorganise ROM files in the development hierarchy. The only other gotcha was that the eye-catcher sprite bank for LOSJ was at $6F, residing in the 2nd pair of sprite files, which required tweaking in my conversion tool. But as of tonight, selecting legendos on MAME runs Knight Lore!
Tomorrow I'll hopefully complete the CPC graphics conversion.
Tuesday, 16 February 2016
-cpc option
A bit more progress today. I've implemented the hflip for CPC graphics. I've also added support for the CPC panel rendering, which differs quite a bit from the ZX version because of the split scroll sprite data. Still a glitch or two to fix, but it's looking more-or-less like it should.
I've added a command-line option (soft dipswitch on the Neo Geo) for selecting the graphics set. I still need to set the palette correctly for the CPC graphics, which will require some research on my part and possibly tweaks to the panel graphics on some ports.
I've yet to create the CPC sprite tileset (ROM) for Neo Geo. I'll probably have to create another panel as well to support the correct palette - that's a bit fiddly. Lastly, I'll add the CPC title screen for when that graphics set is selected.
Oh and I somehow broke the Amiga port. It hangs on the menu screen... :(
UPDATE: Fixed the Amiga port. Need to add support for rendering CPC graphics.
One thing I could do is convert the ZX Spectrum graphics to the same format as the CPC, or better yet, a format more suitable for the target platforms to simplify code and improve performance. But I probably won't. I think the C port has been a lot more of a diversion than I originally planned.
CPC graphics with a glitch or two |
I've yet to create the CPC sprite tileset (ROM) for Neo Geo. I'll probably have to create another panel as well to support the correct palette - that's a bit fiddly. Lastly, I'll add the CPC title screen for when that graphics set is selected.
Oh and I somehow broke the Amiga port. It hangs on the menu screen... :(
UPDATE: Fixed the Amiga port. Need to add support for rendering CPC graphics.
One thing I could do is convert the ZX Spectrum graphics to the same format as the CPC, or better yet, a format more suitable for the target platforms to simplify code and improve performance. But I probably won't. I think the C port has been a lot more of a diversion than I originally planned.
Sunday, 14 February 2016
More CPC analysis
Not much time on the weekends for sitting in front of a computer - except perhaps to print out weird and wonderfully random requests for colouring pages for my daughter - but I have done a little more analysis.
The two sprite entries that now point to NULL were both sprites used for the tree walls (2 of 3). I can only assume that they've been replaced by the two extra sprites at the end of the table. The ZX version of Knight Lore has a common update routine for all 3 wall sprites that is simply a fixed offset for rendering. Why didn't they simply didn't add an extra update routine for the aforementioned two? Time will tell.
The location tables for both versions are identical. I'm expecting differences in the background type table for the tree walls that of course point to the new sprite entries. Again, time will tell.
I'm hoping the differences are restricted to what I've seen thus far; would be nice to have a simple soft dipswitch setting on the Neo Geo for ZX or CPC graphics! I'm debating whether I should bother porting the CPC loading/title screen across too...
UPDATE: The foreground (block) type table is, as hoped, also identical. That just leaves the background type table which, as expected, differs. Thankfully only a little, though somewhat surprisingly at that.
What wasn't expected was a few sprites in the (brick) wall have slightly different Y & Z offsets. The update routines are the same (same pixel offset adjustments) so good news so far.
What was expected were differences in the tree wall. I did expect the walls to include the extra sprites at the end of the sprite table. Instead, the two missing sprites are simply replaced by flipped versions of the 1st sprite! Careful comparison of screen shots from CPC and other versions confirm this. I can't fathom why they would have deemed this necessary?
What this strongly suggests, however, is that the extra sprites aren't actually used without some behind-the-scenes hackery. Shortly I'll print the sprite table and see what they actually are. On that note, I'll also compare all the sprite dimensions to ensure that they're compatible with the ZX version.
One last difference; sprite #184 has its own update routine now, which copies some bytes into a RAM location I'm not familiar with and then falls through to the familiar ZX routine. What is interesting about this is that #184 is the sprite that the collapsing block changes to, leading to the bug I mentioned a few posts ago. Without further analysis I can't say whether this is a fix for the bug, but it certainly didn't look like it at first glance.
UPDATE #2: Quite a few sprites differ in height. A few differ in width. Hopefully it won't be an issue if I use the graphic data from the CPC version with the CPC sprites...
UPDATE #3: There don't appear to be any differences in the code for the different sprites. For the most part, the differences can be explained by the shaving off of the top/bottom line of the mask from various sprites.
The sun/moon frame has been made wider, no doubt to mask the sun/moon at each end; this was accomplished by setting attributes to black on the ZX Spectrum and is currently still an issue in my C port. The scroll sprite has also been truncated.
The extra sprites comprise a number of blocks (purpose unknown) and the body and other end of the truncated scroll. Not really sure why this was necessary... wouldn't appear to me to save much - if any - memory.
It would seem that adding support for CPC graphics to my C port would be, for the most part, simply a matter of replacing a few tables. There would have to be some adjustments made for the frame and perhaps the scroll, at the least. Since both of these are part of the FIX layer on the Neo Geo, they could be all-but-ignored for that port, though I may have to tweak the data to allow me to set the CPC palette for the panel.
UPDATE #4: Got vflip implemented, but not hflip yet for CPC graphics.
The two sprite entries that now point to NULL were both sprites used for the tree walls (2 of 3). I can only assume that they've been replaced by the two extra sprites at the end of the table. The ZX version of Knight Lore has a common update routine for all 3 wall sprites that is simply a fixed offset for rendering. Why didn't they simply didn't add an extra update routine for the aforementioned two? Time will tell.
The location tables for both versions are identical. I'm expecting differences in the background type table for the tree walls that of course point to the new sprite entries. Again, time will tell.
I'm hoping the differences are restricted to what I've seen thus far; would be nice to have a simple soft dipswitch setting on the Neo Geo for ZX or CPC graphics! I'm debating whether I should bother porting the CPC loading/title screen across too...
UPDATE: The foreground (block) type table is, as hoped, also identical. That just leaves the background type table which, as expected, differs. Thankfully only a little, though somewhat surprisingly at that.
What wasn't expected was a few sprites in the (brick) wall have slightly different Y & Z offsets. The update routines are the same (same pixel offset adjustments) so good news so far.
What was expected were differences in the tree wall. I did expect the walls to include the extra sprites at the end of the sprite table. Instead, the two missing sprites are simply replaced by flipped versions of the 1st sprite! Careful comparison of screen shots from CPC and other versions confirm this. I can't fathom why they would have deemed this necessary?
What this strongly suggests, however, is that the extra sprites aren't actually used without some behind-the-scenes hackery. Shortly I'll print the sprite table and see what they actually are. On that note, I'll also compare all the sprite dimensions to ensure that they're compatible with the ZX version.
One last difference; sprite #184 has its own update routine now, which copies some bytes into a RAM location I'm not familiar with and then falls through to the familiar ZX routine. What is interesting about this is that #184 is the sprite that the collapsing block changes to, leading to the bug I mentioned a few posts ago. Without further analysis I can't say whether this is a fix for the bug, but it certainly didn't look like it at first glance.
UPDATE #2: Quite a few sprites differ in height. A few differ in width. Hopefully it won't be an issue if I use the graphic data from the CPC version with the CPC sprites...
UPDATE #3: There don't appear to be any differences in the code for the different sprites. For the most part, the differences can be explained by the shaving off of the top/bottom line of the mask from various sprites.
The 2-tone sprites of Amstrad CPC Knight Lore |
The extra sprites comprise a number of blocks (purpose unknown) and the body and other end of the truncated scroll. Not really sure why this was necessary... wouldn't appear to me to save much - if any - memory.
It would seem that adding support for CPC graphics to my C port would be, for the most part, simply a matter of replacing a few tables. There would have to be some adjustments made for the frame and perhaps the scroll, at the least. Since both of these are part of the FIX layer on the Neo Geo, they could be all-but-ignored for that port, though I may have to tweak the data to allow me to set the CPC palette for the panel.
UPDATE #4: Got vflip implemented, but not hflip yet for CPC graphics.
CPC graphics WIP |
Saturday, 13 February 2016
Two-tone graphics
Taking a break from sprite priorities, curiosity got the better of me and I decided to take a look at how easy or otherwise it would be to rip the graphics from the Amstrad CPC version.
Knowing absolutely zero about the platform, and never having even run a CPC emulator before, it was surprisingly easy to get up-and-running and within half an hour I was disassembling the CPC version of Knight lore!
On the surface it looks a lot closer to the MSX version than the ZX Spectrum version. They've also obviously had to optimise it for space; they've eliminated the unused 4 bytes in the graphics object table, and reduced the maximum number of objects.
Early days yet but I've located the sprite data table and I'm a little perplexed. For starters, they've reorganised the order of sprites in the table (no big deal because there's a table of pointers to each sprite which can't be changed). The sprite width is double the ZX Spectrum counterpart, but the number of bytes in the table is the same, except for the addition of 1 extra byte!
I'll need to study the sprite rendering routine in detail to work out what's going on of course. I've also seen a couple of sprites that are 1 or 2 lines shorter/taller than the ZX equivalent. I'm hoping that's simply an optimisation for space, and that the adjustment values in the update routines haven't changed - because that would be a disaster and probably render the exercise not feasible.
Just for some eye candy, this the the CPC version...
UPDATE: With the benefit of a decent night's sleep, it's immediately obvious that the sprite (data) width (in bytes) is twice that of the ZX Spectrum version because there's 2BPP. And the data size is the same because there's no need for a mask (which can actually be thought of as a 2nd colour plane) in this instance.
A little more disassembling this morning reveals that the extra byte follows the width and height specifiers and appears to be 0 in every sprite. The flip_sprite() routine duly ignores this byte, though it remains to be seen if the code writes to it at any point.
A couple of sprite table entries differ in that they (instead) point to the NULL sprite, and there's six (6) additional entries to the sprite table, including graphics for two (2) additional sprites. I'm yet to investigate which they are.
Next task is to analyse the sprite data to determine if it's 100% compatible with the ZX spectrum version. That means comparing the sprites (by eye), the widths and heights and the purpose of the extra sprites. Then I can make a call as to whether it's possible to simply paste the sprite data into the current C port or whether it would require tweaks to the code.
Knowing absolutely zero about the platform, and never having even run a CPC emulator before, it was surprisingly easy to get up-and-running and within half an hour I was disassembling the CPC version of Knight lore!
On the surface it looks a lot closer to the MSX version than the ZX Spectrum version. They've also obviously had to optimise it for space; they've eliminated the unused 4 bytes in the graphics object table, and reduced the maximum number of objects.
Early days yet but I've located the sprite data table and I'm a little perplexed. For starters, they've reorganised the order of sprites in the table (no big deal because there's a table of pointers to each sprite which can't be changed). The sprite width is double the ZX Spectrum counterpart, but the number of bytes in the table is the same, except for the addition of 1 extra byte!
I'll need to study the sprite rendering routine in detail to work out what's going on of course. I've also seen a couple of sprites that are 1 or 2 lines shorter/taller than the ZX equivalent. I'm hoping that's simply an optimisation for space, and that the adjustment values in the update routines haven't changed - because that would be a disaster and probably render the exercise not feasible.
Just for some eye candy, this the the CPC version...
Example screen shot I ripped from the net. |
A little more disassembling this morning reveals that the extra byte follows the width and height specifiers and appears to be 0 in every sprite. The flip_sprite() routine duly ignores this byte, though it remains to be seen if the code writes to it at any point.
A couple of sprite table entries differ in that they (instead) point to the NULL sprite, and there's six (6) additional entries to the sprite table, including graphics for two (2) additional sprites. I'm yet to investigate which they are.
Next task is to analyse the sprite data to determine if it's 100% compatible with the ZX spectrum version. That means comparing the sprites (by eye), the widths and heights and the purpose of the extra sprites. Then I can make a call as to whether it's possible to simply paste the sprite data into the current C port or whether it would require tweaks to the code.
The fat lady hasn't started singing just yet...
I thought I'd give a brief run-down of the process that Knight Lore uses to render each frame. I won't go into any of the algorithms, but just give an overview of the steps involved.
As I've mentioned previously, Knight Lore builds and maintains a table of objects in the current room. The objects comprise absolutely everything that describes a room, from the background objects (eg walls and arches), both animated (eg guards, ghosts) and inanimate (eg. blocks, spikes) objects, special objects and of course the player himself. The table contains all there is to know about an object, including 2D and 3D positions & dimensions, sprite number, adjustments and current state. A nice architecture and trivial to add new objects with new behaviour.
The first order of business in rendering a new frame is to iterate through the object table and call the update routine - from a lookup table - for each object. The update routines vary in complexity from simply specifying pixel offset for display, to essentially being part of a larger state machine that controls movement, object life-cycle, appearance and interaction with other objects. If an object has changed position or appearance, it flags itself for wiping and redrawing.
Once all the objects have been updated with new state information, the code iterates through the object table again and builds a list (array) of objects that have been flagged for redrawing.
Next the code iterates through the above-mentioned list, looking for those objects which have been flagged for wiping. For these objects, the rectangular (dirty) area to wipe is calculated from its previous and next (2D) sprite position and dimensions, and the off-screen buffer is subsequently wiped. A list of these wiped rectangles is maintained for later blitting to the video memory (screen).
Penultimately, the code examines the list of objects to draw again, and calculates the display order (Z-order), rendering a sprite when it finds nothing else in the list obscured by it. It's then marked as drawn, and processing starts over on the list again, until all objects have been rendered. This is the clever bit, and the algorithm whose minute details still elude me.
Lastly, the aforementioned blitting can be done, resulting in the absolute minimum area (more-or-less) of the screen being copied each frame. And thusly the display is updated.
My C port faithfully reproduces the behaviour of the Z80 code, and works flawlessly on those systems I've ported it to that have bitmapped displays. And in typical fashion, I assumed I could mimic the correct behaviour on a system with a requisiste number of sprites - namely the Neo Geo - without actually devising an algorithm up-front. And if you've read this blog the last few days, you'll know that I've failed to do so thus far.
Last post I lamented on the very real possibility that it couldn't be done with only the information imparted during the rendering process I described above, by the code base as-is. However my 1-year-old had his shots yesterday so I was up for an hour last night trying to get him to sleep, giving me plenty of time to agonise over Knight Lore, and the issue at hand.
One thing I did realise, that has given me some new hope, is this; up until now I've been processing the list of objects that need to be redrawn each frame. That list comprises objects that have been affected by foreground objects but have themselves remained unchanged. And on a sprite-based system, those objects I can completely ignore!
Rather, at least with respect to objects (sprites) that may need moving and/or shuffling of display order (sprite priority), I need concern myself only with the list of objects that have been wiped! These objects have either moved, changed appearance, or disappeared altogether. And it only took about 2 minutes to modify my algorithm to prove it. So far so good.
Exactly if/how this fact contributes to a full solution to the problem I am yet to determine, and I'm not about to predict anything given my recent track record.
That aside, I've been thinking about the worst-case scenario (rendering all objects every frame) and how I'd go about optimising the rendering should I need to defer to this case. I've got a few ideas, but at this stage I don't have a feel for how the 68K would handle the extra processing, and/or whether the bottleneck exists in the sheer number of sprites to re-build each frame.
Any readers that have any theories/ideas - I'd be more than happy to hear them!
EDIT: Another little optimisation I thought about last night; not all sprites require 3x4 Neo Geo sprite tiles. In fact, a lot are considerably less. Given that writing to VRAM (sprite registers) is quite inefficient, reducing that to the minimum should increase the number of sprites that can be written per frame. I've just implemented that.
As I've mentioned previously, Knight Lore builds and maintains a table of objects in the current room. The objects comprise absolutely everything that describes a room, from the background objects (eg walls and arches), both animated (eg guards, ghosts) and inanimate (eg. blocks, spikes) objects, special objects and of course the player himself. The table contains all there is to know about an object, including 2D and 3D positions & dimensions, sprite number, adjustments and current state. A nice architecture and trivial to add new objects with new behaviour.
The first order of business in rendering a new frame is to iterate through the object table and call the update routine - from a lookup table - for each object. The update routines vary in complexity from simply specifying pixel offset for display, to essentially being part of a larger state machine that controls movement, object life-cycle, appearance and interaction with other objects. If an object has changed position or appearance, it flags itself for wiping and redrawing.
Once all the objects have been updated with new state information, the code iterates through the object table again and builds a list (array) of objects that have been flagged for redrawing.
Next the code iterates through the above-mentioned list, looking for those objects which have been flagged for wiping. For these objects, the rectangular (dirty) area to wipe is calculated from its previous and next (2D) sprite position and dimensions, and the off-screen buffer is subsequently wiped. A list of these wiped rectangles is maintained for later blitting to the video memory (screen).
Penultimately, the code examines the list of objects to draw again, and calculates the display order (Z-order), rendering a sprite when it finds nothing else in the list obscured by it. It's then marked as drawn, and processing starts over on the list again, until all objects have been rendered. This is the clever bit, and the algorithm whose minute details still elude me.
Lastly, the aforementioned blitting can be done, resulting in the absolute minimum area (more-or-less) of the screen being copied each frame. And thusly the display is updated.
My C port faithfully reproduces the behaviour of the Z80 code, and works flawlessly on those systems I've ported it to that have bitmapped displays. And in typical fashion, I assumed I could mimic the correct behaviour on a system with a requisiste number of sprites - namely the Neo Geo - without actually devising an algorithm up-front. And if you've read this blog the last few days, you'll know that I've failed to do so thus far.
Last post I lamented on the very real possibility that it couldn't be done with only the information imparted during the rendering process I described above, by the code base as-is. However my 1-year-old had his shots yesterday so I was up for an hour last night trying to get him to sleep, giving me plenty of time to agonise over Knight Lore, and the issue at hand.
One thing I did realise, that has given me some new hope, is this; up until now I've been processing the list of objects that need to be redrawn each frame. That list comprises objects that have been affected by foreground objects but have themselves remained unchanged. And on a sprite-based system, those objects I can completely ignore!
Rather, at least with respect to objects (sprites) that may need moving and/or shuffling of display order (sprite priority), I need concern myself only with the list of objects that have been wiped! These objects have either moved, changed appearance, or disappeared altogether. And it only took about 2 minutes to modify my algorithm to prove it. So far so good.
Exactly if/how this fact contributes to a full solution to the problem I am yet to determine, and I'm not about to predict anything given my recent track record.
That aside, I've been thinking about the worst-case scenario (rendering all objects every frame) and how I'd go about optimising the rendering should I need to defer to this case. I've got a few ideas, but at this stage I don't have a feel for how the 68K would handle the extra processing, and/or whether the bottleneck exists in the sheer number of sprites to re-build each frame.
Any readers that have any theories/ideas - I'd be more than happy to hear them!
EDIT: Another little optimisation I thought about last night; not all sprites require 3x4 Neo Geo sprite tiles. In fact, a lot are considerably less. Given that writing to VRAM (sprite registers) is quite inefficient, reducing that to the minimum should increase the number of sprites that can be written per frame. I've just implemented that.
Friday, 12 February 2016
3rd time lucky?
After going to bed last night I realised the fundamental flaw in my thinking for the previous two algorithms. Interestingly it explains why my first attempt was closer to the mark and, in fact, essentially borrows from both of my previous algorithms. I'm pretty confident now that I've got it right.
The other encouraging realisation is that there shouldn't be anywhere near the amount of priority shuffling that my last attempt required. To some extent that aspect of it will be dependent on the rendering algorithm used in Knight Lore itself which, understandably, is optimised for its own purposes rather than mine. But the proof will be, as they say, in the pudding.
I should get a chance at lunchtime today to implement my latest theory...
UPDATE: I'm feeling pretty disappointed atm because, with the failure of my latest algorithm, I've all-but-concluded that it's simply not possible to re-order the sprite priority based on only what Knight Lore produces for each frame.
The issue is that I need to maintain a Z-order amongst every object in the room, whilst Knight Lore is essentially only interested in maintaining Z-order information for objects that require re-rendering each frame. It's complicated to explain in a few sentences in a rambling blog, but when a sprite changes its priority - eg. you walk in front of a block - there's insufficient information generated to enable me to determine where in the sprite priority list that sprite needs to move to and, more importantly, with respect to which sprites do I need to preserve the priority.
As an experiment I patched Knight Lore to re-render the entire room each frame and, not surprisingly, each frame was subsequently rendered correctly. It was quite slow, though I should note that I hadn't adjusted the main delay loop value, nor attempted to optimise the re-rendering. So I haven't lost all hope; worst case I may be able to optimise enough of the code to have it playable on the Neo Geo's 12MHz 68K.
But first I'm going to revisit the Knight Lore rendering routine. With the amount of pondering I've done over this issue, plus experimentation, I'm hoping I'll understand more of the algorithm itself, and perhaps there will be a way to impart more of the required information down to the rendering routines. For example, grouping the list by sprites that depend upon one-another may be sufficient to avoid re-render the entire room each frame. Time will tell.
It's disappointing because although it has been fun, I've put a lot of effort into this port and the game - with the .data segment issue fixed - will be 99% there, and it looks and plays quite nicely. It would be such a shame not to have it working properly. It's also trivial to add, for example, the CPC two-tone graphics by simply producing a 2nd set of tiles and tweaking the palette. A soft dipswitch option for the graphics would be a no-brainer.
Fingers crossed!
The other encouraging realisation is that there shouldn't be anywhere near the amount of priority shuffling that my last attempt required. To some extent that aspect of it will be dependent on the rendering algorithm used in Knight Lore itself which, understandably, is optimised for its own purposes rather than mine. But the proof will be, as they say, in the pudding.
I should get a chance at lunchtime today to implement my latest theory...
UPDATE: I'm feeling pretty disappointed atm because, with the failure of my latest algorithm, I've all-but-concluded that it's simply not possible to re-order the sprite priority based on only what Knight Lore produces for each frame.
The issue is that I need to maintain a Z-order amongst every object in the room, whilst Knight Lore is essentially only interested in maintaining Z-order information for objects that require re-rendering each frame. It's complicated to explain in a few sentences in a rambling blog, but when a sprite changes its priority - eg. you walk in front of a block - there's insufficient information generated to enable me to determine where in the sprite priority list that sprite needs to move to and, more importantly, with respect to which sprites do I need to preserve the priority.
As an experiment I patched Knight Lore to re-render the entire room each frame and, not surprisingly, each frame was subsequently rendered correctly. It was quite slow, though I should note that I hadn't adjusted the main delay loop value, nor attempted to optimise the re-rendering. So I haven't lost all hope; worst case I may be able to optimise enough of the code to have it playable on the Neo Geo's 12MHz 68K.
But first I'm going to revisit the Knight Lore rendering routine. With the amount of pondering I've done over this issue, plus experimentation, I'm hoping I'll understand more of the algorithm itself, and perhaps there will be a way to impart more of the required information down to the rendering routines. For example, grouping the list by sprites that depend upon one-another may be sufficient to avoid re-render the entire room each frame. Time will tell.
It's disappointing because although it has been fun, I've put a lot of effort into this port and the game - with the .data segment issue fixed - will be 99% there, and it looks and plays quite nicely. It would be such a shame not to have it working properly. It's also trivial to add, for example, the CPC two-tone graphics by simply producing a 2nd set of tiles and tweaking the palette. A soft dipswitch option for the graphics would be a no-brainer.
Fingers crossed!
Thursday, 11 February 2016
Priorities
I've fixed the top-level program flow so that game over returns to the main menu in the absence of setjmp/longjmp - not that I could get them working properly anyway.
During testing I discovered another game play bug; entering a room from an elevated arch leaves you hanging in the air unable to move. Hmm...
Most of my "Knight Lore" time today has been working on Neo Geo Z-ordering, which equates to shuffling hardware sprite priorities.
The first task was to defer actual sprite rendering and instead build a list of sprites to be wiped, and another of sprites to be rendered, for the current frame. The former list will be used when objects disappear from the screen, so I know to park the hardware sprite.
The latter list must be processed against the entire graphic object table in order to re-assign hardware sprite priorities. Here-in lies the challenge of devising an adequate algorithm.
My first algorithm produces almost perfect results; in fact I thought it was working for a while until I entered a rather crowded room and some subtle priority issues arose. After eventually resorting to pencil-and-paper I realised the flaw in the algorithm itself.
Back to the drawing board and I've got another algorithm in mind. It's more complicated and is going to take a bit to implement and get right. Even then, I've no proof the algorithm is correct. The problem is that debugging on the Neo Geo is particularly painful with the lack of stdout for printing debugging information, and it's not possible to debug on, for example, the PC without writing some sort of emulation layer for hardware sprites.
Fun, fun fun!
UPDATE: Implemented my new algorithm tonight. I'm assuming there's no bugs, but the results are worse than the simpler algorithm. I'm beginning to wonder if there actually is a solution, short of re-rendering every sprite on the screen (and there's no time for that during VBLANK).
During testing I discovered another game play bug; entering a room from an elevated arch leaves you hanging in the air unable to move. Hmm...
Most of my "Knight Lore" time today has been working on Neo Geo Z-ordering, which equates to shuffling hardware sprite priorities.
The first task was to defer actual sprite rendering and instead build a list of sprites to be wiped, and another of sprites to be rendered, for the current frame. The former list will be used when objects disappear from the screen, so I know to park the hardware sprite.
The latter list must be processed against the entire graphic object table in order to re-assign hardware sprite priorities. Here-in lies the challenge of devising an adequate algorithm.
My first algorithm produces almost perfect results; in fact I thought it was working for a while until I entered a rather crowded room and some subtle priority issues arose. After eventually resorting to pencil-and-paper I realised the flaw in the algorithm itself.
Algorithm #1 - gets it right most of the time |
Back to the drawing board and I've got another algorithm in mind. It's more complicated and is going to take a bit to implement and get right. Even then, I've no proof the algorithm is correct. The problem is that debugging on the Neo Geo is particularly painful with the lack of stdout for printing debugging information, and it's not possible to debug on, for example, the PC without writing some sort of emulation layer for hardware sprites.
Fun, fun fun!
UPDATE: Implemented my new algorithm tonight. I'm assuming there's no bugs, but the results are worse than the simpler algorithm. I'm beginning to wonder if there actually is a solution, short of re-rendering every sprite on the screen (and there's no time for that during VBLANK).
Wednesday, 10 February 2016
Not my bug!
I've finally squashed a long-standing bug in the game play of my C port that resulted in the player dropping through the floor and wrapping around to the top of the screen indefinitely. It was most easily reproduced by jumping on a collapsing block (eg. room #230) but I had seen it on other occasions in the past.
The kicker is, the bug is in the original ZX Spectrum Z80 code!
Not much point going into detail but, in a nutshell, the code was de-referencing a pointer that was NULL in certain circumstances, but the code never expected it to be so, and hence never checked it. Given the code in question handles two quite different object types, it's likely the programmers simply called the prior routine for the 2nd object thinking it was sufficient.
The end result of the bug is that, on the ZX Spectrum, it writes a zero to location zero, which happens to be ROM and therefore benign. I've actually verified this is the case using the MESS debugger.
I also suspect it's also the case with the MSX port, and is certainly the case on my TRS-80 port.
So my C port must of course check for a 'NULL POINTER' in this routine. It's slightly more involved than that, but that's the gist of it.
Hopefully that's the last of the bugs in the C port, though I'm still yet to play through a complete game. I will release an update of the Amiga port and perhaps someone else can beta-test it for me!
P.S. The Amiga port got a mention on www.indieretronews.com!
The kicker is, the bug is in the original ZX Spectrum Z80 code!
Not much point going into detail but, in a nutshell, the code was de-referencing a pointer that was NULL in certain circumstances, but the code never expected it to be so, and hence never checked it. Given the code in question handles two quite different object types, it's likely the programmers simply called the prior routine for the 2nd object thinking it was sufficient.
The end result of the bug is that, on the ZX Spectrum, it writes a zero to location zero, which happens to be ROM and therefore benign. I've actually verified this is the case using the MESS debugger.
I also suspect it's also the case with the MSX port, and is certainly the case on my TRS-80 port.
So my C port must of course check for a 'NULL POINTER' in this routine. It's slightly more involved than that, but that's the gist of it.
Hopefully that's the last of the bugs in the C port, though I'm still yet to play through a complete game. I will release an update of the Amiga port and perhaps someone else can beta-test it for me!
P.S. The Amiga port got a mention on www.indieretronews.com!
I can C colours!
Quick Knight Lore update - I have added (ZX Spectrum) colour support to all the C platforms (allegro, amigaos & neogeo). Granted it's garish, but a little more interesting to look at than monochrome.
After adding colour support to Neo Geo initially, the code was a bit of a dog's breakfast. Today whilst working on allegro and amigaos ports, I managed to tidy up the colour support quite a bit, simplifying it in the process.
The other change I made was to re-organise the font data, so that the C code could simply print ASCII strings directly, rather than having to map each character to the original Z80 font codes. The up-side of this was the removal of two OS-dependent print routines, further simplifying the platform-specific modules. There's remarkably very little code for each port now!
So what I have left to complete on the C ports are:
I'm hoping to have the C ports complete sometime in the next week or so. I'll then release the C project in its entirety and then get started on what was the original goal - a TRS-80 Color Computer 3 (Coco3) port. Not a C port (though I'm curious to know if it would run on a 25MHz Coco3FPGA), but rather re-coding the entire game in 6809 assembler for eventual release on cartridge.
After adding colour support to Neo Geo initially, the code was a bit of a dog's breakfast. Today whilst working on allegro and amigaos ports, I managed to tidy up the colour support quite a bit, simplifying it in the process.
The other change I made was to re-organise the font data, so that the C code could simply print ASCII strings directly, rather than having to map each character to the original Z80 font codes. The up-side of this was the removal of two OS-dependent print routines, further simplifying the platform-specific modules. There's remarkably very little code for each port now!
So what I have left to complete on the C ports are:
Long-standing game play bug(s) when stepping onto collapsing block- Initialisation of missing data structures (neogeo)
- Z-order sprite sorting (neogeo)
Game over to return properly to main menu- (Possibly) display loading screen (amigaos)
- (Possibly) add directional control game play option
- (Possibly) add sound to some ports
I'm hoping to have the C ports complete sometime in the next week or so. I'll then release the C project in its entirety and then get started on what was the original goal - a TRS-80 Color Computer 3 (Coco3) port. Not a C port (though I'm curious to know if it would run on a 25MHz Coco3FPGA), but rather re-coding the entire game in 6809 assembler for eventual release on cartridge.
Tuesday, 9 February 2016
Neo Geo MVS Eye Candy
Panel Review
Got the panel displaying nicely now. Just the border around the main menu to complete, then that's the graphics done except for the title screen.
The scrolls and the frame comprise a complete bank of FIX layer tiles covering the bottom 8 lines of the screen. I patched the Knight Lore C source code to display only these elements of the panel, with some extra flood fills for masking around the frame so it doesn't have the same issue with the other C ports, namely the sun showing on the left of frame. Then updated the graphics conversion tool to generate the FIX layer tiles, and it's good to go.
The lives graphic, objects carried and sun/moon are all sprites that appear through the FIX layer panel's transparency mask. The number of lives, "DAY" and day counter are FIX layer tiles that replace the panel tiles when printed.
It's looking the business now. As mentioned, main menu border, title screen, and sprite Z-ordering to be done. Then there's the issue of the few auto-initialised arrays that need to be copied to RAM for modification by running code so that it plays correctly.
I should be able to add colour to the Neo Geo port quite easily. I'll tackle that when everything else has been sorted.
I'm also considering porting the directional control option from the original source; I'd omitted that until now because it was only ever running on keyboard systems. I'll also have to re-work the menu operation for the Neo Geo if I do that, or simply add a DIPSWITCH option instead.
Panel graphics complete |
The lives graphic, objects carried and sun/moon are all sprites that appear through the FIX layer panel's transparency mask. The number of lives, "DAY" and day counter are FIX layer tiles that replace the panel tiles when printed.
It's looking the business now. As mentioned, main menu border, title screen, and sprite Z-ordering to be done. Then there's the issue of the few auto-initialised arrays that need to be copied to RAM for modification by running code so that it plays correctly.
I should be able to add colour to the Neo Geo port quite easily. I'll tackle that when everything else has been sorted.
I'm also considering porting the directional control option from the original source; I'd omitted that until now because it was only ever running on keyboard systems. I'll also have to re-work the menu operation for the Neo Geo if I do that, or simply add a DIPSWITCH option instead.
Monday, 8 February 2016
Const-ant issues
After much head-scratching and reading notes on the devkit I've managed to fix the display issues. There are still problems that I'm not going to be able to solve without making allowances in the core Knight Lore code.
As explained in the devkit notes (which I found at the bottom of a locked filing cabinet stuck in a disused lavatory with a sign on the door saying beware of the leopard) the .data section is discarded on cartridge systems. Fair enough - I simply need to declare constant auto-initialised data as const. Only that doesn't always work. So I had to resort to using gcc's attribute property to specify the segment. Thankfully that was sufficient.
There are still a few data arrays that need initialising, but are also modified by the code. I'll need to define them as const and then makes copies in RAM before the main code runs.
I've hooked up the joystick input and can actually play the game. I need to get Z-order sorted next.
UPDATE: I've added the font to the FIX layer and display the menu and some panel information.
The last sections to display are the scrolls that delineate the panel and the frame around the sun/moon. For this I'll define a special bank in the FIX layer.
Sprites are now rendered at the correct coordinates |
There are still a few data arrays that need initialising, but are also modified by the code. I'll need to define them as const and then makes copies in RAM before the main code runs.
I've hooked up the joystick input and can actually play the game. I need to get Z-order sorted next.
UPDATE: I've added the font to the FIX layer and display the menu and some panel information.
Showing elements from the FIX layer |
^%$!@#$ compiler issues
Several compiler issues to contend with, including all sorts of issues with const.
But I have managed to get something to appear, and the game is running and animating...
As earlier in the development phase, there's no Z-order processing atm. But it's still very promising at this stage. The Y-offset on the arches is peculiar...
But I have managed to get something to appear, and the game is running and animating...
Room #31 - Neo Geo MVS |
Friday, 5 February 2016
Neo Geo MVS on MAME
Had some playing around to get Knight Lore compiling under Neo Geo again, and then duly discovered how much I've forgotten about Neo Geo development! Managed to recall just enough to get some tiles showing...
As interesting aside... in the SOFT DIP BIOS screen it was still showing "LODE RUNNER". After checking the makefile and all the intermediate output files, the only explanation left was MAME running an old version of the development ROM (puzzledp). Nope.
Then something came back to me. If the game has NVRAM saved, it reads the game name and the settings back from the save, and doesn't use the name in the ROM header! Since the Knight Lore cartridge currently has the same GUID in the ROM header as Lode Runner, it thought it was the same game and used an old NVRAM save. Trap for young players...
UPDATE: It's slowly coming back to me...
A random assortment of Knight Lore tiles - Neo Geo MVS under MAME |
Then something came back to me. If the game has NVRAM saved, it reads the game name and the settings back from the save, and doesn't use the name in the ROM header! Since the Knight Lore cartridge currently has the same GUID in the ROM header as Lode Runner, it thought it was the same game and used an old NVRAM save. Trap for young players...
UPDATE: It's slowly coming back to me...
That looks a little more organised |
Thursday, 4 February 2016
Neo Geo
I've managed to build the sprites for the Neo Geo port.
I thought I'd blog a bit (more) about the process I use when converting graphics for various ports. As I've stressed a few times now, the goal is always to preserve the original pixels but of course porting to different platforms often requires converting those pixel to different formats, and the Neo Geo is one of the more extreme examples.
I always like to roll my own tools (not that I've seen many ZX Spectrum Filmation Engine-to-Neo Geo conversion utilities out there) and my weapons of choice are C and the Allegro graphics library on the PC. And after using these to develop tools for many of my own little projects, I find I'm cutting-and-pasting more code than I'm writing for each new project - which is a good thing - and this latest tool was no exception.
Now although the ZX Spectrum is a purely bit-mapped system, and the Neo Geo is little more than a sprite engine, Knight Lore (the filmation engine) renders all graphics as "sprites" and this is the only reason that a Neo Geo port is even possible. Even then I'll need to make special allowances in the core for the Neo Geo (or more generically, hardware sprites) but at this point, given my past experience with Neo Geo development, I do believe it can be done.
First order of business is converting all the "sprites" from the Knight Lore sprite table into Neo Geo (MVS) tiles. For reasons I won't go into at this point, the most efficient way to organise the Neo Geo sprite tiles is to assume all "sprites" are the same size. It transpires that the largest sprite in Knight Lore is 5 bytes by 64 lines (40x64 pixels) so I've made each Neo Geo equivalent 4x4 tiles (64x64 pixels).
You might also notice that there are duplicate sprites. These are due to different objects having the same graphical representation. Not surprisingly, Knight Lore uses a lookup table to avoid such a waste of memory. However on the Neo Geo, we have a ridiculous number of tiles available and duplicating the tiles means one less level of indirection (better performance) in the sprite rendering. For those curious, this increases the number of distinct sprites from 103 to 188. That translates to no less than 3,008 tiles.
For simplicity, I've simply mapped the sprite mask to bit-plane 0, and the sprite pixels to bit-plane 1. That results in 4 colours; 0 (transparent), 1 is the mask which I will set to black, and 2 & 3 which need to be set to the same colour (eg. white) to show the correct result.
The filmation engine supports horizontal and vertical flipping of sprites. The Neo Geo also supports the same, in hardware. At first glance it seems a no-brainer, but given that the sizes of Knight Lore sprites vary, and those of the Neo Geo are fixed, it's not that simple. One solution is to keep a table of sprite dimensions and offset the sprite if flipped. A more efficient solution - on the Neo Geo at least - is to create versions of each sprite (tile) in all combinations of flip. So there'll be four (4) copies of each sprite, and now we're talking 12,032 tiles (and that doesn't include tiles required for the Neo geo BIOS, nor the Knight Lore font)! On any other system that'd be out of the question, but on the Neo Geo, it's chump-change.
So right now I have a tool that converts Knight Lore sprites to Neo Geo sprite tiles (the C ROMs). The tool then re-reads the resultant files and displays the tiles on the PC using Allegro. This code was lifted directly from a previous tool so I do actually know that the tile format is correct.
As I eluded to above, there are still two (2) fonts to extract from Knight Lore, used on the main menu and the panel (status) display. These are modest in comparison and will use only a handful of tiles.
In the mean-time, I should be able to use what I have and get a crude rendering of the main display happening. It will require some modifications to core engine, but I've done similar for the Lode Runner port some time back.
Knight Lore Neo Geo tiles showing mask |
I thought I'd blog a bit (more) about the process I use when converting graphics for various ports. As I've stressed a few times now, the goal is always to preserve the original pixels but of course porting to different platforms often requires converting those pixel to different formats, and the Neo Geo is one of the more extreme examples.
I always like to roll my own tools (not that I've seen many ZX Spectrum Filmation Engine-to-Neo Geo conversion utilities out there) and my weapons of choice are C and the Allegro graphics library on the PC. And after using these to develop tools for many of my own little projects, I find I'm cutting-and-pasting more code than I'm writing for each new project - which is a good thing - and this latest tool was no exception.
Now although the ZX Spectrum is a purely bit-mapped system, and the Neo Geo is little more than a sprite engine, Knight Lore (the filmation engine) renders all graphics as "sprites" and this is the only reason that a Neo Geo port is even possible. Even then I'll need to make special allowances in the core for the Neo Geo (or more generically, hardware sprites) but at this point, given my past experience with Neo Geo development, I do believe it can be done.
First order of business is converting all the "sprites" from the Knight Lore sprite table into Neo Geo (MVS) tiles. For reasons I won't go into at this point, the most efficient way to organise the Neo Geo sprite tiles is to assume all "sprites" are the same size. It transpires that the largest sprite in Knight Lore is 5 bytes by 64 lines (40x64 pixels) so I've made each Neo Geo equivalent 4x4 tiles (64x64 pixels).
You might also notice that there are duplicate sprites. These are due to different objects having the same graphical representation. Not surprisingly, Knight Lore uses a lookup table to avoid such a waste of memory. However on the Neo Geo, we have a ridiculous number of tiles available and duplicating the tiles means one less level of indirection (better performance) in the sprite rendering. For those curious, this increases the number of distinct sprites from 103 to 188. That translates to no less than 3,008 tiles.
For simplicity, I've simply mapped the sprite mask to bit-plane 0, and the sprite pixels to bit-plane 1. That results in 4 colours; 0 (transparent), 1 is the mask which I will set to black, and 2 & 3 which need to be set to the same colour (eg. white) to show the correct result.
The filmation engine supports horizontal and vertical flipping of sprites. The Neo Geo also supports the same, in hardware. At first glance it seems a no-brainer, but given that the sizes of Knight Lore sprites vary, and those of the Neo Geo are fixed, it's not that simple. One solution is to keep a table of sprite dimensions and offset the sprite if flipped. A more efficient solution - on the Neo Geo at least - is to create versions of each sprite (tile) in all combinations of flip. So there'll be four (4) copies of each sprite, and now we're talking 12,032 tiles (and that doesn't include tiles required for the Neo geo BIOS, nor the Knight Lore font)! On any other system that'd be out of the question, but on the Neo Geo, it's chump-change.
So right now I have a tool that converts Knight Lore sprites to Neo Geo sprite tiles (the C ROMs). The tool then re-reads the resultant files and displays the tiles on the PC using Allegro. This code was lifted directly from a previous tool so I do actually know that the tile format is correct.
As I eluded to above, there are still two (2) fonts to extract from Knight Lore, used on the main menu and the panel (status) display. These are modest in comparison and will use only a handful of tiles.
In the mean-time, I should be able to use what I have and get a crude rendering of the main display happening. It will require some modifications to core engine, but I've done similar for the Lode Runner port some time back.
Amiga - done and dusted
I've taken the Amiga port as far as the PC-based Allegro port. The game is now fully playable
It's been a whirlwind exercise the last few days, and it's entirely possible (even probable) that my Amiga
code is absolute rubbish. For those in the know, I create a custom
screen (no window) and attach a custom bitmap and specify the palette. I also
maintain another bitmap for off-screen rendering, which I access via
memory pointers to the bitmap plane memory. Then I use the blit functions to move areas from the buffer to the screen. For the keyboard input, I create a message port and read the matrix.
It runs on AmigaOS 3.1 and - presumably - higher. There are still a few kinks but my goal wasn't - at least at this point - to have a polished commerical-grade product. There is still one annoying bug in the C game port that causes the player to fall through the floor... can't reproduce it reliably yet so there's not much I can do about it.
EDIT: Looks like the aforementioned bug is triggered by walking on a collapsing block!
It also requires that you click on the screen with the mouse after running the game, or key presses will be directed to the shell and pause execution whenever the game outputs to stderr. I'm still looking for a solution to that one. The Amiga developer scene is almost non-existent; the few forums I have visited today have only a handful of posts from the last few years.
The 68020-based A1200 can easily cope with the speed - there's a delay in the main loop.
And it still locks up at game end, as it does on the PC.
I might try to fix the keyboard focus issue but soon I'll move onto the Neo Geo. It is going to require a completely different approach to the graphics, as there is no bitmap, only sprites. I have been thinking about it over the last few months and I think I've worked out how to approach it. The somewhat tedious and error-prone part is converting all the graphics across.
UPDATE: Removed stderr output and uploaded AmigaOS binary
Original ZX Spectrum Knight Lore for the Amiga - fully playable |
It runs on AmigaOS 3.1 and - presumably - higher. There are still a few kinks but my goal wasn't - at least at this point - to have a polished commerical-grade product. There is still one annoying bug in the C game port that causes the player to fall through the floor... can't reproduce it reliably yet so there's not much I can do about it.
EDIT: Looks like the aforementioned bug is triggered by walking on a collapsing block!
It also requires that you click on the screen with the mouse after running the game, or key presses will be directed to the shell and pause execution whenever the game outputs to stderr. I'm still looking for a solution to that one. The Amiga developer scene is almost non-existent; the few forums I have visited today have only a handful of posts from the last few years.
The 68020-based A1200 can easily cope with the speed - there's a delay in the main loop.
And it still locks up at game end, as it does on the PC.
I might try to fix the keyboard focus issue but soon I'll move onto the Neo Geo. It is going to require a completely different approach to the graphics, as there is no bitmap, only sprites. I have been thinking about it over the last few months and I think I've worked out how to approach it. The somewhat tedious and error-prone part is converting all the graphics across.
UPDATE: Removed stderr output and uploaded AmigaOS binary
Wednesday, 3 February 2016
Amiga
Not bad for a few hours work. It's currently using the most fundamental graphics functions - SetAPen() and WritePixel() - and rendering directly to the Raster Port rather than an off-screen buffer, but at least it's looking good so far!
It exits the main game function after rendering the room and before the player appears (i.e. it crashes) but I'm happy with the progress none-the-less. I should note that it has been at least a quarter of a century since I last wrote any Amiga software!
EDIT: It wasn't a crash, but the keyboard routines returning wrong values - the game runs and objects are animated. I've also got it rendering now to an off-screen bitmap (plane) and then it blits to the display. Can't find a function that will fill a rectangular area on a bitmap (as opposed to a RastPort). Oh and it does actually crash eventually...
UPDATE: Found a way to clear a rectangular area on a bitmap. Changed screen to LORES. I need to work out how to change the palette on my custom screen.
It's not rendering the sun properly - I commented-out the routine for the moment - and it crashes when day turns to
night. Could be bad coordinates in my sun/moon routine... but it's
getting there. Need to add keyboard input next.
This screen looks familiar... just before the game exits. |
It exits the main game function after rendering the room and before the player appears (i.e. it crashes) but I'm happy with the progress none-the-less. I should note that it has been at least a quarter of a century since I last wrote any Amiga software!
EDIT: It wasn't a crash, but the keyboard routines returning wrong values - the game runs and objects are animated. I've also got it rendering now to an off-screen bitmap (plane) and then it blits to the display. Can't find a function that will fill a rectangular area on a bitmap (as opposed to a RastPort). Oh and it does actually crash eventually...
UPDATE: Found a way to clear a rectangular area on a bitmap. Changed screen to LORES. I need to work out how to change the palette on my custom screen.
Animating on the Amiga LORES screen |
Tuesday, 2 February 2016
MSX and reverse-engineered code releases
Curiosity got the better of me at lunchtime today and I took a quick look at the official Knight Lore cartridge for the MSX computer.
The core itself is identical of course, with the main differences in the system setup and hardware interfaces, most noticeably the video access routines. I was surprised they did move a couple of routines around, and there's a few more variables for as-yet-unknown purposes, but it's unmistakably a straight adaptation of the Spectrum code.
Give the almost trivial code changes I did for the TRS-80 port, I was expecting the code to more closely resemble the original. But there appears to be just a little too much MSX-specific code required for me to bother with a port of a game that already has a port. If I'm honest, I'm starting to tire of the filmation games and I need to move on to my original goal before I lose interest altogether.
On another note, I decided there was no reason not to release my reverse-engineered code listings for various projects in the past. So now you'll find disassemblies for Apple II Lode Runner, MSX Lode Runner (partial), TRS-80 Tandy Invaders, and source for the Microbee port of the same - all on my Project List page.
Enjoy!
EDIT: No luck installing the Amiga development environment on my work PC tonight...
The core itself is identical of course, with the main differences in the system setup and hardware interfaces, most noticeably the video access routines. I was surprised they did move a couple of routines around, and there's a few more variables for as-yet-unknown purposes, but it's unmistakably a straight adaptation of the Spectrum code.
Give the almost trivial code changes I did for the TRS-80 port, I was expecting the code to more closely resemble the original. But there appears to be just a little too much MSX-specific code required for me to bother with a port of a game that already has a port. If I'm honest, I'm starting to tire of the filmation games and I need to move on to my original goal before I lose interest altogether.
On another note, I decided there was no reason not to release my reverse-engineered code listings for various projects in the past. So now you'll find disassemblies for Apple II Lode Runner, MSX Lode Runner (partial), TRS-80 Tandy Invaders, and source for the Microbee port of the same - all on my Project List page.
Enjoy!
EDIT: No luck installing the Amiga development environment on my work PC tonight...
Monday, 1 February 2016
Pentagram on the TRS-80
They say practice makes perfect, and porting filmation games to the TRS-80 is certainly no exception. The third and final installment - Pentagram - is now running, albeit slowly.
Initially I was a little surprised that the game runs so noticeably slower than the previous two titles, however on reflection there is a fair bit of additional code manipulating the graphics objects that I'm yet to reverse-engineer.
I should also reiterate that the TRS-80 code is still a quick hack and far from optimal.
I also discovered the pause control (SPACEBAR) in all three games, and have updated (my copies of) the disassemblies accordingly. I have also implemented pause in the Pentagram TRS-80 port.
As was the case for Alien 8, I think there's little value in taking this disassembly too much further for the purposes of implementing Knight Lore on the Coco3 or any other platform for that matter. I don't believe the core filmation engine is any more enhanced (or even faster) than that originally coded for Knight Lore. I might check my theory on the shooting, but I'll leave the remainder of the program as an exercise for later (or others).
Preliminary alpha disassembly and TRS-80 binary available.
Next? Another Z80 port to the Australian-made Microbee (Premium) is on the cards. I'm considering then tackling the Amiga and Neo Geo ports (of my C source) - they shouldn't take a huge amount of time, and then I'll get stuck into the Coco3 6809 port of Knight Lore.
Pentagram title screen on the TRS-80 |
A rather busy screen on the TRS-80 |
Initially I was a little surprised that the game runs so noticeably slower than the previous two titles, however on reflection there is a fair bit of additional code manipulating the graphics objects that I'm yet to reverse-engineer.
I should also reiterate that the TRS-80 code is still a quick hack and far from optimal.
I also discovered the pause control (SPACEBAR) in all three games, and have updated (my copies of) the disassemblies accordingly. I have also implemented pause in the Pentagram TRS-80 port.
As was the case for Alien 8, I think there's little value in taking this disassembly too much further for the purposes of implementing Knight Lore on the Coco3 or any other platform for that matter. I don't believe the core filmation engine is any more enhanced (or even faster) than that originally coded for Knight Lore. I might check my theory on the shooting, but I'll leave the remainder of the program as an exercise for later (or others).
Preliminary alpha disassembly and TRS-80 binary available.
Next? Another Z80 port to the Australian-made Microbee (Premium) is on the cards. I'm considering then tackling the Amiga and Neo Geo ports (of my C source) - they shouldn't take a huge amount of time, and then I'll get stuck into the Coco3 6809 port of Knight Lore.
More on Pentagram
I've finished the first pass labeling the routines and formatting the data for Pentagram.
Some interesting observations. I would have to say that Pentagram was definitely based on the Alien 8 source code, but there is at least one routine that was lifted from Knight Lore rather than Alien 8. The routine in question has the same net effect - so no good reason for doing so, in fact the Alien 8 version was unrolled to (presumably) run faster - which suggests that perhaps Pentagram was started before Alien 8 was finished!?!
Seemingly for no good reason, the memory map of the game differs from the previous games. The former had variables, then font, game layout and graphic data, and then code, which included the sprite update jump table, strings etc. Pentagram starts with game layout and graphic data, followed by variables, sprite update jump table and then code. Inexplicably, the font data is right in the middle of the sprite data - I suspect the graphics data resided in multiple include files and no-one noticed the font data splitting the sprite data in two.
Knight Lore has a maximum of 40 objects at each location, Alien 8 has 56 (hence the slower rendering) and Pentagram 54. In what may be a bug in Pentagram, the list of objects to draw is only 48 bytes long (same as Knight Lore); not long enough if every object needs redrawing! Again, was that a bug fixed in Alien 8 after the source was forked for Pentagram?
I've seen no evidence (yet) that the filmation engine core itself has been enhanced. The 3D maths, including Z-ordering, all appear to be identical to the previous games.
I've yet to definitively identify the code responsible for the mechanics of re-spawning monsters and shooting, but I've got a pretty good idea of how it would be done. Rather than requiring an extension to the core per se, they should simply be implemented in the sprite update routines; at least, that's the way I would have done it. A testament to the quality and flexibility of the original design!
There are a number of routines called from the main game loop that manipulate objects that are new to Pentagram, which I would say comprise the main differences in the Pentagram source code. At this point I'm not sure what they do.
Based on the work I've done so far, I would say that producing a relocatable version and patching it for the TRS-80 wouldn't be out of the question in the near future.
Some interesting observations. I would have to say that Pentagram was definitely based on the Alien 8 source code, but there is at least one routine that was lifted from Knight Lore rather than Alien 8. The routine in question has the same net effect - so no good reason for doing so, in fact the Alien 8 version was unrolled to (presumably) run faster - which suggests that perhaps Pentagram was started before Alien 8 was finished!?!
Seemingly for no good reason, the memory map of the game differs from the previous games. The former had variables, then font, game layout and graphic data, and then code, which included the sprite update jump table, strings etc. Pentagram starts with game layout and graphic data, followed by variables, sprite update jump table and then code. Inexplicably, the font data is right in the middle of the sprite data - I suspect the graphics data resided in multiple include files and no-one noticed the font data splitting the sprite data in two.
Knight Lore has a maximum of 40 objects at each location, Alien 8 has 56 (hence the slower rendering) and Pentagram 54. In what may be a bug in Pentagram, the list of objects to draw is only 48 bytes long (same as Knight Lore); not long enough if every object needs redrawing! Again, was that a bug fixed in Alien 8 after the source was forked for Pentagram?
I've seen no evidence (yet) that the filmation engine core itself has been enhanced. The 3D maths, including Z-ordering, all appear to be identical to the previous games.
I've yet to definitively identify the code responsible for the mechanics of re-spawning monsters and shooting, but I've got a pretty good idea of how it would be done. Rather than requiring an extension to the core per se, they should simply be implemented in the sprite update routines; at least, that's the way I would have done it. A testament to the quality and flexibility of the original design!
There are a number of routines called from the main game loop that manipulate objects that are new to Pentagram, which I would say comprise the main differences in the Pentagram source code. At this point I'm not sure what they do.
Based on the work I've done so far, I would say that producing a relocatable version and patching it for the TRS-80 wouldn't be out of the question in the near future.