Sunday, December 31, 2017

Fixing a few rendering glitches and re-testing enhanced sprite modes.

While I continue to work on some of the missing hardware items, such as cartridge support, I find I have quite a bit of time waiting for synthesis runs to complete for the FPGA. For the MEGA65 PCB these can take anywhere between 1 and 10 hours.  So, I am using some of that latent time to work on fixing some rendering glitches that have snuck in with the whole move to 800x600 video modes.

Exhibit A: Bitmap mode glitch.  Initially I suspected that the problem here was that each 8x8 block was rotated by one physical pixel -- and that may well have been the case, but after attempting to fix that, a glitch remained.  This is really annoying, because it is super ugly. First step to fixing a problem is to fully understand it.  So I switched the MEGA65 to bitmap mode, and drew some dots, and set different background colours on the 8x8 blocks, so that I could see what was going on:

Well, it is nice to see that there is no rotation, as the top pixl is two physical pixels high. Instead, the problem is the bottom physical pixel row of the last VIC-II logical pixel row in each card.  A bit of poking about, as above, made it clear to me that the problem is that the last physical pixel row is being drawn from the next 8x8 block down, instead of the correct one.  This is easy to fix, by using a version of the row counter that has been delayed by one physical raster line.  Ok. That's that one with a fix (but we will have to wait for synthesis, before knowing for sure).

The other is that expanded sprites seem to be a little too narrow. This results in some annoying artifacts, e.g., in Boulder Dash, where the black bar beneath the core is actually made with a bar of expanded sprites.  Here is a quick shot of the problem taken as  my son was coincidentally playing Boulder Dash as I wrote this post.

 The little vertical bars beneath the score line are the problem we are talking about here.  Looking closer on the screen, I can see that these are one 320x200 pixel wide, i.e., half an expanded sprite pixel. This makes me suspect that the odd/even toggle for working out which half of an expanded sprite pixel is being drawn might be the problem.  Let's test that theory by drawing a simple sprite, expanding it, and seeing if any of the pixels are only 1/2 width.

First, unexpanded:

This revealed something I hadn't previously noticed, but am not surprised to see:  The bottom physical pixel has been shaved off.  Since sprites are effectively expanded vertically the whole time on the MEGA65, they also have an odd/even toggle.  This reinforces my suspicion that those toggles are possibly to blame.

Now expanded in both X and Y directions:

We can see that the left half a pixel has been trimmed when the sprite is expanded, and the bottom half of the last pixel is always missing, whether expanded or not.

Looking through the code, I can see that the odd/even toggle in the X direction doesn't get reset at the end of a sprite. This is quite easy to fix, by resetting it each time a sprite starts drawing on a raster line.  I've written a fix for this now, as well, which will also have to wait for synthesis to see if it has fixed the problem.

The missing row (or rows of pixels) on the bottom is not quite so straight forward.  Here unexpanded, we are seeing one physical row of pixels is missing.  When expanded, it is difficult to tell if we are seeing only two physical rows of the four we should be getting, or whether we are getting three. The difference is important, as each result would suggest different root causes. If two, then the sprite expander is probably to blame.  If three, then it is the double-scanning of the screen that is probably to blame.

To answer this question, I switched back to text mode, and drew some characters on the screen that would let me determine exactly how high that bottom pixel block is:

Here we can see a couple of very interesting things:

First, the sprite is mis-aligned with the text area by one physical 800x600 pixel vertically, rather than on a VIC-II pixel boundary.  That will have to get fixed, as well. But more importantly for now, we can see three whole pixels in the grey box, plus the 1 phsyical pixel = 1/4 of a vertically expanded sprite pixel, an the lower sprite pixel block, just above the A, ends exactly on the bottom of the grey box. That is, we have 1/4 + 1 + 1 + 1 + x = 4 pixels. Thus x must be 3/4 of a pixel high, and must therefore be missing only the bottom physical pixel.

This means that it is our scan-doubling that is the problem. Looking at the code, the end of sprite is determined based on reaching the last pixel in the sprite. However, since multiple physical rasters may have the same VIC-II raster number, we should instead check for the first raster after the end of the sprite, and stop drawing there, instead. Again, once identified, the (hopeful) fix, is quite simple, and will be thrown into the next synthesis run.

While I am here working on sprites, it also gives me the opportunity to re-test some of the MEGA65 enhanced sprite modes, to make sure that those still work.

We have:

Super-hires sprites (enabled for all by bit for in $D054), which also doubles the sprite X resolution. We will be using these in the special MEGA65 version of GEOS, so that the mouse-pointer is also hi-res, and can point at any pixel. If you use it with multi-colour mode, it effectively gives you 320x200 4-colour sprites. Yup, super-hires sprites still seems to work.

Extended height mode (enabled with one bit per sprite in $D055, and the height /of the sprites set by $D056, up to 255 pixels high). Yup, that seems to work.


Extended width mode (64 pixels wide, instead of the usual 24, enabled per sprite by bits of $D057). Yup, that too. So far so good. This mode will also be useful with the super-hires mode and multi-colour mode, to allow sprites to be 32x21 (or 32 x extended sprite height) hi-res pixels in size, but with three colours.

Bitplane mode sprites (sprite modifies one of the bits in output colour, instead of setting colour, enabled by upper bits in $D049 and $D04B). Yup, that, too.

And finally, horizontal tiling mode, where the same 24 or 64 bits of sprite data are repeated until the edge of the screen is reached. Yup, that works, and also confirms that bitplane mode sprites (for better or for worse) currently ignore the presence of the border.

I thought I had also implemented 16-colour sprite mode, where 4 bits are used together for each pixel (so they will be either 6 or 16 pixels wide, depending on whether extended width mode is used), but apparently not. I might have to revisit that, as it won't be hard to add, but will certainly make the 8 sprites we have go further, and will also make it possible to have interesting colourful backgrounds when used with tile mode.  

I'd be interested to hear how people think they might use these enhanced sprite modes, or whether there is something obvious that I have missed.

But for now, it is the impatient wait while these changes synthesise, and hopefully, fix those annoying display glitches.

No comments:

Post a Comment