SPRITE_RAM_ENABLE problems

Topics related to the API, programming discussions & questions, coding tips, bugs, etc. should go here.
Post Reply
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

SPRITE_RAM_ENABLE problems

Post by nicksen782 »

SPRITE_RAM_ENABLE=1 is in my Makefile.

Here is a modification to MapSprite2. This operates somewhat like MapSprite2 but the map comes from ram. The tilemap looks similar too except the tile ids are vram ids. That means that flash tiles are += RAM_TILES_COUNT. The SPRITE_RAM flag will be set if the tile is a ram tile. Otherwise, it is the same.

** edit:: CODE HAS BEEN CORRECTED. If the sprite_bank for the flash tiles is NOT 0 then you must specify it. Also, I make sure to clear the sprite_bank flags if the tile is a ram tile.

Code: Select all

void MapSprite2_nra( unsigned char startSprite, const char *map, u8 spriteFlags ) {
	// Similar syntax to MapSprite2. Supports all sprite flags such as: SPRITE_FLIP_X, SPRITE_FLIP_Y, SPRITE_OFF.
	 // The map uses vram ids (not the normal tile ids.)
	 // SPRITE_RAM is set automatically as determined by the value of the vram id.
	  // If an individual tile is < RAM_TILES_COUNT then SPRITE_RAM in spriteFlags will be set for that tile.
	// The map is expected to be from ram.
	// After being mapped, MoveSprite can be used as expected.

	u8 mapWidth  = map[0]; // Tilemap width.
	u8 mapHeight = map[1]; // Tilemap height.
	u8 x;                  // Starting X origin.
	u8 y;                  // Starting Y origin.
	s8 dx;                 // Destination X position.
	s8 dy;                 // Destination t position.
	u8 t;                  // Tile id.

	// SPRITE_FLIP_X and SPRITE_FLIP_Y are used to determine the draw order of the map.
	// The kernel will take care of the actual sprite flipping on x and/or y.
	if(spriteFlags & SPRITE_FLIP_X){ x=(mapWidth-1); dx=-1; }
	else{ x=0; dx=1; }
	if(spriteFlags & SPRITE_FLIP_Y){ y=(mapHeight-1); dy=-1; }
	else{ y=0; dy=1; }

	// Go through the map and adjust the values in the sprites array.
	for(u8 cy=0;cy<mapHeight;cy++){
		for(u8 cx=0;cx<mapWidth;cx++){
			// Get the vram tile id.
			t=map[ (y * mapWidth) +x +2 ] ;

			// Set the tile id and the sprite flags.

			// Is this a ram tile?
			if( t < RAM_TILES_COUNT ){
				// Set the tile id to be the tileIndex of this sprite entry.
				sprites[startSprite].tileIndex=t;
				// Set the SPRITE_RAM flag in spriteFlags of this sprite entry based on the value of the tile id.
				// Make sure that a spritebank is NOT set for this.
				sprites[startSprite].flags = spriteFlags | SPRITE_RAM & ~(
					SPRITE_BANK0 |
					SPRITE_BANK1 |
					SPRITE_BANK2 |
					SPRITE_BANK3
				) ;
			}
			// This is a flash tile. Use the specified spriteFlags (which should also include the SPRITE_BANK if it is not SPRITE_BANK0.)
			else{
				sprites[startSprite].tileIndex=t-RAM_TILES_COUNT;
				sprites[startSprite].flags = spriteFlags ;
			}

			// Advance x.
			x+=dx;

			// Advance to the next sprite.
			startSprite++;
		}

		// Advance y.
		y+=dy;

		// Set the next x position.
		x = (spriteFlags & SPRITE_FLIP_X) ? (mapWidth-1) : (0);
	}

}
I think my code is correct but I am having a problem specifically with the flash tiles. They don't work. I get garbage.

Looking at kernel/videoMode3/videoMode3core.s on line 1152 I see an #if. It looks like BlitSpritePart can do do ram tile sourced or flash tile sourced, but not both. Am I correct? What I do is copy a vram region to get tile ids and I prepend the width and height value. Some of those tiles are flash and some are ram tiles.

Could a modification be made that would allow for usage of the kernel sprite blitter AND be able to source sprite tiles from EITHER flash or ram?
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: SPRITE_RAM_ENABLE problems

Post by nicksen782 »

The most simple solution could be to copy/paste BlitSpritePart into something like BlitSpritePart2 (or better names.)

One of the functions could be for blitting flash tiles and the other for ram tiles.

I'm sure there is a much better way to do this without all the duplicate code. It appears that the only difference would be the instructions used for reading from each source. Unfortunately, I don't know the ASM syntax to do that. I do also understand that the C function that calls BlitSpritePart would need to have an "if" in there to determine which of the two ASM functions to call.

Perhaps someone with more kernel experience could take a look?
User avatar
Jubatian
Posts: 1560
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: SPRITE_RAM_ENABLE problems

Post by Jubatian »

Huh, sorry, didn't check in here since a few days.

This part ideally should be working, with SPRITE_RAM_ENABLE=1 the expected behaviour is that the SPRITE_RAM flag will have its effect. If it is OFF, you should have a ROM sourced sprite. Did you confirm whether the ROM sprites actually work when SPRITE_RAM_ENABLE is zero on your code?

I don't see anything obvious in the kernel which would prevent it working, the RAM sprite addition is quite simple, barely touching the original flow. Broken RAM sprites would actually be a more expectable outcome if anything if there was a bug there. I tested a compile with SPRITE_RAM_ENABLE=1 on the Super Mario Demo, and it kept working just fine (expected behaviour).
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: SPRITE_RAM_ENABLE problems

Post by nicksen782 »

I may have jumped to conclusions here since I haven't seen anyone using ramtile sprites and definitely not mapping sprites that have both ram and flash tiles in them. Being able to read the ASM would have helped but it doesn't appear to be broken into functions. More like, labels and gotos. Is that how it works?

If you look at my sample code above you can see how I'm mapping the sprite. I just check if < RAM_TILES_COUNT and if so then set the flag. The ram tile sprites work just fine. The flash ones do not. If I remove the flag in the Makefile for ramtile sprites then none of it works. So, there's that.

At least I know that the kernel is fine. I'll do some more tests and report back here. Thank Jubation for clearing my kernel concern!
User avatar
Jubatian
Posts: 1560
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: SPRITE_RAM_ENABLE problems

Post by Jubatian »

There are functions in that assembly, however that BlitSpritePart is indeed a large one to understand.(function entry points and thus boundaries in the Mode 3 assembly file are marked with similar heading like BlitSpritePart has). However I believe that one should do what it is supposed to be doing.

I can not really help a lot more on this one, since you are using that part of the mode which I never checked out or modified (maybe fixed some bug in it at some point though), the original high level sprite engine. I would expect that possibly the mechanism of setting up the data source for flash tiles might have some problem.

The low level sprite blitter uses the user RAM tiles for RAM sourced sprites, while otherwise it uses the sprite tile banks. Indices overlap between those two (both are indexed zero based). Also there are multiple ROM sprite banks (optionally) to allow for more than 256 (ROM) sprite tiles.
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: SPRITE_RAM_ENABLE problems

Post by nicksen782 »

So, I suddenly figured it out.

sprites[startSprite].flags = spriteFlags | SPRITE_BANK1;

I'm setting SPRITE_BANK1 into the spriteFlags. If you do not do this then you get SPRITE_BANK0. I set SPRITE_BANK0 to my cursor sprite tiles and SPRITE_BANK1 to my bg tiles. I did not specify SPRITE_BANK1.

Thank you very much! I'm back to working on my game. I updated the function that I included at the top of this post. You really do need to send the SPRITE_BANK value if not using SPRITE_BANK0 which is the default. Also, the function unsets the SPRITE_BANK flags if the tile in the map is a ramtile.
User avatar
Jubatian
Posts: 1560
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: SPRITE_RAM_ENABLE problems

Post by Jubatian »

nicksen782 wrote: Thu Apr 11, 2019 8:52 pmAlso, the function unsets the SPRITE_BANK flags if the tile in the map is a ramtile.
This shouldn't be necessary as it looks like the blitter would ignore the bank anyway if it is blitting a RAM sourced sprite. Maybe try it, if it doesn't work this way, I would say it is a bug.

Glad you found it though, no more headaches! :)
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: SPRITE_RAM_ENABLE problems

Post by nicksen782 »

There may in fact be a bug then. I purposely set a sprite bank for the ram tiles and I got glitched tiles. So, now I just clear the sprite bank flags when making a sprite sourced from a ram tile.

Progress continues!
User avatar
Jubatian
Posts: 1560
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: SPRITE_RAM_ENABLE problems

Post by Jubatian »

Analyzing the code didn't quite get me anywhere. As far as I see the bank in the low level blitter is only used at a single location (top of BlitSpritePart) which is skipped when blitting a RAM sourced sprite, in the assembly, the case is pretty clear. The C code it is a bit more difficult to follow, but I don't see anything either. I am uncertain on the high level sprite engine as it uses some rather ambiguous constructs which without the exact knowledge of precedence rules can not be resolved for certain. It needs some actual debugging (if you had code available, I could look into it, without that, I would rather postpone).
User avatar
nicksen782
Posts: 714
Joined: Wed Feb 01, 2012 8:23 pm
Location: Detroit, United States
Contact:

Re: SPRITE_RAM_ENABLE problems

Post by nicksen782 »

I just tested this again. I had this initially and it works. Notice that it clears all the sprite_bank flags?

sprites[startSprite].flags =
spriteFlags |
SPRITE_RAM & ~( SPRITE_BANK0 | SPRITE_BANK1 | SPRITE_BANK2 | SPRITE_BANK3 ) ;

So then I tried to code in a sprite bank:
sprites[startSprite].flags =
spriteFlags |
SPRITE_RAM | SPRITE_BANK0 ;

And it works. I must have forgotten the SPRITE_RAM flag in my test. Seems I don't need that top example (in this post) anymore.

Thanks for looking into it!
Post Reply