Attribute updates

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

If you need 72 bytes for this complicated scheme to work, why not just go all the way and mirror the whole attribute tables and use 128 bytes? It's not that much more, and will keep you from having this sliding buffer.

But if you do want to stick to that "shifting" scheme, that can usually be done by not shifting at all, but having a pointer indicate which entry represents the leftmost column.

From your example, this variable would start as "0". But once you scrolled 32 pixels, the $00 is not the first any more, $55 is. So, instead of shifting the whole thing left, have the variable move right, incrementing it to 1. Of course, this changes the way you access that buffer. Instead of counting X bytes from the start of the row, you count X bytes from what the variable indicates is the first byte in the row. Continuing the example, the row now starts at position 1, and you have to update the byte at the other edge, 8 bytes later. So you add 8 to the variable (which holds 1) and you get 9. Since this value is beyond your range (0 to 8), you subtract 9 from it, and the result is 0, which is indeed the last byte in the row now. So you replace the $55 in there with the new $EF.

In fact, since you know that last byte of the row is the one located before the first, it'd be better to subtract one from the variable instead of adding 8. The range check would be simpler, as you would just need to check if the result was negative, in which case you make it wrap to 8. The effect is exactly the same.

The only complicated part is that now some math is required to calculate the exact index of the byte in the row you haveto change, but still much less than sifting that number of bytes.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

tokumaru wrote:If you need 72 bytes for this complicated scheme to work, why not just go all the way and mirror the whole attribute tables and use 128 bytes? It's not that much more, and will keep you from having this sliding buffer.
You know, that's not a bad idea. I could really benefit from this, and you're right, I wouldn't have to deal with the shifting thing. I'd already have all the information I'd need right in the table.
tokumaru wrote: The only complicated part is that now some math is required to calculate the exact index of the byte in the row you haveto change, but still much less than sifting that number of bytes.
Math is no problem for me. Everything in my scrolling/updating engine is calculated using the value of the scroll variables, or distorted scroll values. Calculating the index will be very easy, I think. But that's a very good idea to have the 2 attribute tables both in RAM. I think I'll have each row in RAM be 2 side by side rows of attributes. So $200-$207 is $23C0-$23C8, and $208-20F is $27C0-$23C8. That will make it very much easier.

EDIT: I didn't see your post until now Tepples. My shift wouldn't have been that simple. Because if you just do that, what will happen is the attribute which would go to $23C8, which is at the left side of the screen, would be shifted to $23C7, which obviously is something someone would not generally want. I think I'll just stay away from shifts though.
Drag
Posts: 1350
Joined: Mon Sep 27, 2004 2:57 pm
Contact:

Post by Drag »

I'm planning my scrolling engine out, and I've also run into an attribute issue.

If I'm scrolling to the right, the attribute data has to be written in a column from top to bottom. Now, the issue I'm having is that it doesn't matter whether I have a copy of the attribute data in the ram or whether I just grab it from $2007, when updating a column of attribute data, I need to write to every 8th byte, and there's really no good way to do this other than resetting $2006 for each write, whereas updating a row is simply just write write write write 'kay done.

And I'm doing 8-way scrolling, "rolling" with both axes, using horizontal mirroring (like Kirby's Adventure).

But yeah, is there any more of an efficient way to update a column of attribute data than to just reset $2006 for each write? (by resetting, I mean manually incrementing the address by $08, and rewriting the incremented value)
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Drag wrote:But yeah, is there any more of an efficient way to update a column of attribute data than to just reset $2006 for each write? (by resetting, I mean manually incrementing the address by $08, and rewriting the incremented value)
I don't think so. I also got very upset because of this a while ago... it would be useful if the PPU had an "increment 8" mode, as it has "increment 1" and "increment 32". I don't think thisis such a problem though, because it's just so little data... you'll most likely update only 9 bytes, so the overhead of setting the address before each write is not so bad.

At one point I even though about coding a very efficient routine to copy the whole 128 bytes of the attribute tables mirror every frame, but now I realize that would be insane.
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

Drag wrote:I need to write to every 8th byte, and there's really no good way to do this other than resetting $2006 for each write
Use the increment 32 mode anyway, just interleave the tiles. 4 passes will be just like update 8.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
Drag
Posts: 1350
Joined: Mon Sep 27, 2004 2:57 pm
Contact:

Post by Drag »

That's a good idea, actually. I'd still need to play around with the pointers used to access the attribute data in the ram (if I decide to put it in the ram).

It's probably a better idea to have the attribute in the ram for me, because I have a status bar, and the way it works is that the two nametables are the same, except one of them (the one on the bottom) contains the graphics for the status bar, so every write I make to the PPU would need to be doubled to the other nametable, while making sure not to overwrite the status bar.

I don't think this is inefficient, because Gargoyle's Quest II does this exact thing, exactly the way I was going to do it (Kirby's Adventure mirrors the screen with a reduced height, whereas Gargoyle's Quest II just simply mirrors the two nametables, without disturbing the status bar on the one nametable)

Thanks for the help! :D
Post Reply