Mode 3 with scrolling possible bug?

Topics related to the API, programming discussions & questions, coding tips, bugs, etc. should go here.
User avatar
Artcfox
Posts: 1382
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Mode 3 with scrolling possible bug?

Post by Artcfox »

So I've been playing around with Mode 3 with scrolling, and I built myself a little demo program to make sure that I understand how it works.

I've run into some weird behavior which I'm wondering if it's something that I'm doing wrong, or if I found an edge case bug in the kernel's sprite drawing routines that causes the sprite not to draw where it's supposed to.

Here is a YouTube video showing the issue:


Attached is a .uze and .cap that demonstrates the problem, along with the full source code of the demo.

Pressing Up/Down/Left/Right will scroll the screen. Holding BTN_A while pressing Up/Down/Left/Right will move the sprite without scrolling the screen. The problem seems to occur if you move the sprite partially off the left edge of the screen, and then call Scroll with a small negative X value. The pixels in the sprite abruptly stop being drawn, and depending on how much you scroll in Y, they'll either not be drawn at all, be drawn in the wrong spot, or the entire sprite will also be drawn near the origin with various X offsets that change as the Screen.scrollY changes.
Attachments
scroll-source.zip
Full source code to demo
(85.45 KiB) Downloaded 335 times
scroll.zip
.uze and .cap that demonstrates the issue
(7.42 KiB) Downloaded 331 times
User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: Mode 3 with scrolling possible bug?

Post by D3thAdd3r »

Very weird, will take a look later this weekend. First guess would be a bug in Process sprites having to do with the, relatively untested by games, interleaved vram addressing. Ram tiles look blitted ok when present, just in the wrong place.
User avatar
Artcfox
Posts: 1382
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Mode 3 with scrolling possible bug?

Post by Artcfox »

Actually, sometimes it blits the wrong sprite entirely!

I changed the color of sprite 0 so it's easier to see, and I also changed my WaitVsync(1) to WaitVsync(10) to slow it down.

User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: Mode 3 with scrolling possible bug?

Post by D3thAdd3r »

Are you sure that Screen.ScrollX and Screen.ScrollY are never some high number(due to overflow on an unsigned byte)? AFAIK, if you wanted to scroll negative you would need to simulate it by moving all tiles in vram over, then apply the correct positive value that would give the same visual result. Only way I see wrong sprites, is if the offset is way too high due to an overflow sent to BlitSprite()

Code: Select all

typedef struct {
	u8 overlayHeight;
	const char *overlayTileTable;
	#if SCROLLING == 1		  
		[b]u8[/b] scrollX;
		[b]u8[/b] scrollY;
		u8 scrollHeight;
	#endif
} ScreenType;
User avatar
Artcfox
Posts: 1382
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Mode 3 with scrolling possible bug?

Post by Artcfox »

With VRAM being 32 tiles wide, and 32 tiles tall, that gives exactly 256 pixels on a side, so all possible values for scrollX and scrollY should be valid. It doesn't matter which direction I scroll to get there. The same thing happens if I move my sprite to that location by moving and scrolling the screen to the right (using only positive values).

I thought that the great feature of mode 3 with scrolling is you never have to copy all the VRAM tiles into a different spot in VRAM. VRAM can stay unchanged, and it will just start drawing the tiles from a different origin. I looked at the source code for other mode 3 scrolling games, and they also make that assumption. You can scroll indefinitely, and all you ever need to do is to load a new horizontal or vertical stripe into the appropriate place in VRAM if you want to display "new data."

That assumption appears to be correct, in that no matter what the sprite's x and y position is, and no matter what the scrollX and scrollY values are, my collision detection for when the sprite is over a certain tile value works correctly (even when the sprite is set to a pixel address outside of the screen's viewport, but still a valid VRAM address, I can hear it collecting cookies in places where I know they exist).

And if I want a sprite entity to remain static relative to the tiles when I'm scrolling the screen, I just need to subtract the scrollX and scrollY value from the entitiy's "screen" position every time the screen scrolls.

Code: Select all

    // IF YOU WANT A SPRITE at (16, 192) TO SCROLL WITH THE SCREEN
        sprites[0].x = 16 - Screen.scrollX;
        sprites[0].y = 192 - Screen.scrollY;
The only real problems that I'm running into are the edge cases for drawing a sprite that spills over from the last column of VRAM into the first column of VRAM, and only when the scrollX value is close to rolling over.
User avatar
Artcfox
Posts: 1382
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Mode 3 with scrolling possible bug?

Post by Artcfox »

Interestingly, if I change the code to use sprites[1] instead of sprites[0], then the green sprite does not appear at the top of the screen anymore:

User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: Mode 3 with scrolling possible bug?

Post by D3thAdd3r »

Artcfox wrote:With VRAM being 32 tiles wide, and 32 tiles tall, that gives exactly 256 pixels on a side, so all possible values for scrollX and scrollY should be valid.
Nice, this is very useful information to have. I have done so little with scrolling, that a lot of things I have done with it are probably the wrong way.

Don't see anything wrong in your source, and nothing pops out at me in ProcessSprites(). Still, to get the wrong sprite showing up and you are not manually messing with ram_tiles[], there must be something up in ProcessSprites(). There seemingly can't be a bug in BlitSprite that would do that, but if passed bad values, it could draw the wrong one. Past that, nothing else messes with anything sprite related than ram_tiles_restore[], I think.
User avatar
Artcfox
Posts: 1382
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Mode 3 with scrolling possible bug?

Post by Artcfox »

Lee, thanks for pointing me to the ProcessSprites function! Luckily for me it is written in C. Within the first 10 seconds of looking at it, the exact same bug that I fixed yesterday in my demo program jumped right out at me:

Code: Select all

void ProcessSprites(){
...
    unsigned int ramPtr,ssx,ssy;
...
    //get tile's screen section offsets
                                
    #if SCROLLING == 1
        ssx=sprites[i].x+Screen.scrollX;
        ssy=sprites[i].y+Screen.scrollY;
    #else
Except in my case it was the C language that was converting intermediate math results in an expression up into 16-bit, and I had been counting on the automatic wrapping of an 8-bit value. In this case, ssx and ssy are actually 16-bits, meaning that wrap never happens!

I made this change:

Code: Select all

diff --git a/kernel/videoMode3/videoMode3.c b/kernel/videoMode3/videoMode3.c
index de2df13..18963dc 100644
--- a/kernel/videoMode3/videoMode3.c
+++ b/kernel/videoMode3/videoMode3.c
@@ -147,8 +147,8 @@
 
        void ProcessSprites(){
        
-               unsigned char i,bx,by,dx,dy,bt,x,y,tx=1,ty=1,wx,wy;
-               unsigned int ramPtr,ssx,ssy;
+               unsigned char i,bx,by,dx,dy,bt,x,y,tx=1,ty=1,wx,wy,ssx,ssy;
+               unsigned int ramPtr;
 
                if(!spritesOn) return;
so that ssx and ssy are now 8-bit, to let that wrap happen automatically!

Since I had recorded a .cap file, I was able to play it back and see if that fixed things:


Woohoo!!! No more weird behavior!!! :D

I still want to hammer on it some more to see if I can break it again (and to make sure that the rest of the mode 3 with scrolling programs still run correctly), but so far that looks good to me!
User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: Mode 3 with scrolling possible bug?

Post by D3thAdd3r »

Excellent work! I added a bug report on GitHub linking back to this thread. So hopefully next version it will not be forgotten to apply your fix.
User avatar
Artcfox
Posts: 1382
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Mode 3 with scrolling possible bug?

Post by Artcfox »

D3thAdd3r wrote:Excellent work! I added a bug report on GitHub linking back to this thread. So hopefully next version it will not be forgotten to apply your fix.
Thanks! :)

I've had it in the back of my mind that I should make a tutorial about mode 3 with scrolling, since there isn't already one, and it's a subject that I've had a mental block about for quite some time now. So far two people have expressed interest, so I'll probably write one that goes through the same process that I'm using to learn about it. Taking the step-by-step approach that I've done so far has really cemented some of the concepts in my head, and this little demo provides a good playground for testing edge cases. (I had assumed that I would be testing the edge cases in my code, but apparently it also covers edge cases in the kernel, which is good too!) For it to be a better test though, I should really get rid of the spinning cookies and use square treasures so it's possible to see exactly where the sprites cross the tile boundaries. I might leave out the animations too, just to simplify things even more.
Post Reply