+  RHDN Forum Archive
|-+  Romhacking
| |-+  General Romhacking
| | |-+  Unwanted Palette Swapping
Pages: [1]
Author Topic: Unwanted Palette Swapping  (Read 1 times)
Knirt
Guest
« on: August 10, 2009, 03:45:58 pm »

Hello guys!
I'm doing a translation from English to Portuguese, it's from the NES game "The 3D Battles of the World Runner". But my problems here aren't related to translation itself, but more with Romhacking, that's why this topic's here.

Well, I've decided to edit the Title-Screen, while maintaning the original name of the protagonist (named - what a surprise - World Runner Tongue). Then I've changed the graphics in the top of the screen. The problem is, on the bottom of the screen used to exist one phrase that would blink all the way. I've believe this effect is obtained via palette-swapping, though I'm not sure.

Well, the problem is that this effect was carried to a part of my edited graphic. And that's awfully bad, as the effect is completely unwanted and more, unexpected. Here are some pictures of what I'm talking about:

Original Picture:


Modified Picture:


I've tried to re-map these tiles that are unwantedly blinking, but I've got no luck. In the process I've screwed the edge of "World", but this I can handle, and'll correct later. I was afraid that I couldn't solve this problem just by messing with the graphics editor, than I went to some ASM hack, that I'm just a newbie.
Using FCEUX 2.2.1 RAM Filter, I was able to discover that the address $00E4 is the one that changes accordingly to the blinking. I went to the debugger, placed the breakpoint, and found the piece of code that messes with it (at least in the menu part). Every run of this address is linked with an INC command, but I got no luck in interpreting the routines.

And them I'm here, asking for some help. What do you guys think this might be? Is it really palette swapping? If so, any way I can modify it without having to use Debugger and ASM Hack? Thanks.
Tauwasser
Guest
« Reply #1 on: August 10, 2009, 04:10:57 pm »

You probably found the routine that changes the palette. What you are looking for is the tilemap that assigns a palette for every tile on-screen. I believe for NES they are usually called name tables. Info on that can be found with FCEUX (I saw screenshots of it having a tilemap viewer).
Basically, it is going to be either of two cases:
  • the tilemap is copied 1:1 to RAM -- this is the easy type
  • the tilemap is created via a routine -- this will require asm work

Basically, there is going to be a routine that creates the map in RAM. If it is a 1:1 copy, you got lucky and you can just change the stuff in the original data and that's it. If you have to deal with a routine that draws these maps, you will have to find it and change its vectors according to your desires.

Also, another route to get around this problem is by simply not using the shade that is blinking - if you have another shade available that has the same color or can be changed to the same color without corrupting the rest of the title screen. This is oobviously the cheap way out and may not be possible in your case. You should try to break inside the routine that is executed when the values for the tilemap change in ram.

Also, you should probably wait till Disch sees this thread, he is much more knowledgeable and may have some other clues as far as terminology goes Cheesy

cYa,

Tauwasser
tummai
Guest
« Reply #2 on: August 10, 2009, 05:17:44 pm »

The mapping of palettes to onscreen tiles is usually called an "attribute table" or just "attributes" on the NES.  It is the last 64 bytes of each nametable.  What you will want to do is set a breakpoint for writes to PPU Memory $23C0-23FF and see where that data comes from.

When you do check, I think you will be pleased to find that this game copies directly from ROM to RAM, so it will be easy to change the palette for the few tiles you are having problems with. Smiley 

Here is a good explanation of how attribute table data is formatted on the NES.  It should help you if you haven't worked with attributes before:

bunnyboy's tutorial - backgrounds
Knirt
Guest
« Reply #3 on: August 11, 2009, 08:44:02 pm »

Firstly, sorry for taking too long to reply. I had some difficult getting the tutorial at the point you gave me, tummai, so I had to go from the first class. Luckily, I'm now finishing reading about PPU Access (and some of these routines are related to the one I've found and mentioned early in the game), and I'm almost quite understanding the whole process. Not intuitive as I would have though, but with references like this link, the process is more understandable.

Secondly, thanks for the feedback. I wouldn't have expected a doc as nice as this one. Sweet!
Now, just for some considerations (I still have to finish the reading of the docs, so I may say some noobish - if I do so, pardon me ;P): it looks like that, in my picture, everything is considered background. I've came to this conclusion not only because all the graphics were exhibited in the same Name Table, but also because it goes scrolling all at once.

Now, let's say I know the position on the Name Tables of the bytes I want to remove the blinking effect. A simple look at the Name Tables at FCEUX was able to tell me that. There goes also the PPU address of these tiles, and if I would pause the emulation twice, once on each blink color, I would got two palette codes (what makes sense). If I add a breakpoint related to this PPU address, find the routine that changes the palette to these tiles and simply change the value (in a way that it doesn't swap), do you guys think this will work?

And oh, @Tauwasser - sorry, I really didn't got what you tried to say with shades. By saying shades, you mean simply changing the color of the tile? In a simple graphic editor? Sorry, I couldn't really understand this part.

And oh, thanks everybody again.
tummai
Guest
« Reply #4 on: August 12, 2009, 01:00:51 am »

Quote from: Knirt on August 11, 2009, 08:44:02 pm
Now, let's say I know the position on the Name Tables of the bytes I want to remove the blinking effect. A simple look at the Name Tables at FCEUX was able to tell me that. There goes also the PPU address of these tiles, and if I would pause the emulation twice, once on each blink color, I would got two palette codes (what makes sense). If I add a breakpoint related to this PPU address, find the routine that changes the palette to these tiles and simply change the value (in a way that it doesn't swap), do you guys think this will work?

Almost.  If you open the PPU Viewer in FCEUX, you will notice that the palette that color-swaps in the title screen sequence of this game is palette #0 (please check to make sure).  The reason you have unwanted blinking at the top-right of your screen is that the tiles up there are assigned to palette 0.  You can fix this by assigning those tiles to a different palette (palette 1 is probably the one you want).

Palettes are assigned in the Attribute Table (last 64 bytes in the Nametable), so you will want to set a breakpoint to writes to the Attribute Table.  The Attribute Table for the Nametable we are looking at starts at PPU $23C0 and goes to $23FF (64 bytes).  So you can set a breakpoint on writes to PPU $23C0-$23FF.  Then work backwards and find where the values written there are coming from.

Lucky for us, this game stores them uncompressed in ROM (I won't tell you where though.  I want you to find them Smiley ).  That makes them easy to modify.  The last step is to figure out which byte/bytes correspond to your problem tiles and change those bytes to assign a new palette to those tiles.  The pictures at the beginning of that tutorial I linked to will help you figure out how Attribute bytes are mapped to Nametable tiles.

If you have any more questions, feel free to ask Smiley
Knirt
Guest
« Reply #5 on: August 13, 2009, 02:07:06 am »

Okay, in theory, I got it completely. When it's time to put my skills on use, I'm having some difficulties, but I'll tell what I've figured from the last 3 hours reading your post, bunnyboy's tutorial, and mashing through the Debugger and the Name Table.

Firstly, you're right about the palettes. Palette 0 is the one that swaps, while Palette 1 is the one with purple and orange tones that makes almost the entire logo. The exceptions are the green texts, which also use Palette 0, the one that contains this specific tone of green. Palette 2 and 3 doesn't seem to be used on this background at all.

Well, I've quite understood the way that the attribute byte is defined. I've opened a screenshot of the title screen in GIMP and set up a grid of 16x16 tiles, what would represent the Attribute Tables. Follows the picture:



The picture shows that the palettes are being loaded as:
0 0
1 1
We are messing with NES, little endian (is that right? I just know that we must swap the bytes), then the attribute byte would then be: 1 1 0 0 = %01010000 = $50
So we know which byte is being sent to this name table. We must change this $50 to a $55 (so we'll have %01010101 = 1 1 1 1 - then all the bytes of this name table would use Palette 1, the non-blinking one), right?

Now, the last thing we should figure out is the exact address of this nametable, right? I've followed your recomendation (it wasn't clear at the beginning, but I've soon figured out the reason of this address range) and set up a write breakpoint at PPU $23C0 ~ $23FF. The debugger soon halted, and I was directed to a routine very similar to the one mentioned in bunnyboy's tutorial as "LoadAttribute Loop". It would be the following:

00:8123:B1 E0       LDA ($E0),Y @ $87C0 = #$00
00:8125:8D 07 20  STA $2007 = #$00
00:8128:C8           INY
00:8129:D0 F8       BNE $8123

Each time I would hit "Run", the indexed address would increase, and the value loaded from that address could vary. I'm assuming that this indexed address is the place on the ROM where the Attribute Byte's are being stored, is this right? If so, I would be able to navigate manually to that point and simply change the expected $50 to $55, right?

Geez, took me SO long to figure this out, and I'm suspecting this final part won't be so simple. I've learn't debugging with Parasyte's tutorial, and when I've changed Samus jump value, I just made a hex search using the hex sequence found in the debugger, and not really the address found. That's why I'm assuming this supposedly address range that contains the attribute bytes in ROM (what I suspect to be $87C0 ~ $87FF, one for each 2x2 area). Oh geez, it's already past 4AM here in Brazil, I'm probably saying heavy bullshit now >.<

Please, if I said something that makes sense, point it. I'm very glad for all the help you're giving, tummai, and I hope I can finish this translaction before next monday. Vacations are near over ;P
tummai
Guest
« Reply #6 on: August 13, 2009, 09:14:48 am »

Quote from: Knirt on August 13, 2009, 02:07:06 am
Okay, in theory, I got it completely.

Yes, it appears that you do! Smiley  You're so close that I think you will head yourself on the head when you see what's tripping you up.

Quote from: Knirt on August 13, 2009, 02:07:06 am
Well, I've quite understood the way that the attribute byte is defined. I've opened a screenshot of the title screen in GIMP and set up a grid of 16x16 tiles, what would represent the Attribute Tables. Follows the picture:



The picture shows that the palettes are being loaded as:
0 0
1 1
We are messing with NES, little endian (is that right? I just know that we must swap the bytes), then the attribute byte would then be: 1 1 0 0 = %01010000 = $50
So we know which byte is being sent to this name table. We must change this $50 to a $55 (so we'll have %01010101 = 1 1 1 1 - then all the bytes of this name table would use Palette 1, the non-blinking one), right?

You've almost got it!  I don't actually think little endian has anything to do with it.  That just refers to how the CPU works with 16-bit addresses (low byte first, high byte second).  The whole PPU Attribute byte mess is its own monster.  Still, regardless of the reason, you constructed the attribute byte correctly for the block you posted.  %01010000 is right.

But there's one little problem.  A sneaky one too Smiley.  Your block is wrong.  That screenshot you took was in NTSC mode.  NTSC cuts 8 scanlines off the top and bottom, so your GiMP grid of 16x16 will be offset by 8 because the top 8 scanlines aren't displayed in your screenshot.  Open up the game again in FCEUX and go to Config->PAL Emulation and you will see the entire screen.  Then if you take a new screenshot and put up your grid, I think you will find your block will look like this:



Which is:

0 0  <---black
0 0  <---your blinking tiles. change these to 1's and you're done

So you will be looking for an attribute byte that is $00, and you will want to change it to be $50 (%01010000)

Quote from: Knirt on August 13, 2009, 02:07:06 am
Each time I would hit "Run", the indexed address would increase, and the value loaded from that address could vary. I'm assuming that this indexed address is the place on the ROM where the Attribute Byte's are being stored, is this right?

Yes, exactly right.  The routine is copying those bytes directly from ROM to the PPU

Quote from: Knirt on August 13, 2009, 02:07:06 am
If so, I would be able to navigate manually to that point and simply change the expected $50 to $55, right?

Geez, took me SO long to figure this out, and I'm suspecting this final part won't be so simple. I've learn't debugging with Parasyte's tutorial, and when I've changed Samus jump value, I just made a hex search using the hex sequence found in the debugger, and not really the address found. That's why I'm assuming this supposedly address range that contains the attribute bytes in ROM (what I suspect to be $87C0 ~ $87FF, one for each 2x2 area).

As you suspected you will have to find out where in the ROM these bytes are.  At runtime when the debugger snapped, they have been bankswitched into the $87C0-$87FF address space.  There are two ways to do find their location in the ROM:

1) since you know what the bytes are now, you can do a hex search for a string of them (00 40 50 50 50 50 00 00 00 04 05 45 15 05, for example) to find them in the ROM.

2) FCEUX's Hex Editor has a really useful feature.  When the debugger snaps on your breakpoint, open the Hex Editor and go to $87C0.  Right click and choose "Go Here In Rom File".  It will bring you to the real physical address in the Rom file.  Then you can edit the hex values directly in the Hex Editor.

#2 is probably the easiest/fastest way.  BTW, If you try to edit the values in the Hex Editor without doing "Go Here In Rom File" first, it won't work.  Did you try to do that at first?


Quote from: Knirt on August 13, 2009, 02:07:06 am
Please, if I said something that makes sense, point it. I'm very glad for all the help you're giving, tummai, and I hope I can finish this translaction before next monday. Vacations are near over ;P

No problem Smiley.  I think you've gotten the hang of it.  Let me know if you have any more questions.
Knirt
Guest
« Reply #7 on: August 13, 2009, 10:58:57 pm »

Oh, lord.
Actually, tummai, I suspected of this NTSC issue. The reason I suspected is simple, when I opened the Name Table, I would check the X and Y position of the blinking tiles. I'm not sure about the X position, as it doesn't matter for me, but I was certain Y position was 3, counting from 0. Following this logic, the blinking tiles should be at the bottom of a 2x2 area. This is was one of the most annoying things I've faced yesterday, cos' it didn't check with the grid I was setting on GIMP. I even tried to offset 8 tiles up the grid, but it was looking too weird and then I came back to the original setting, which had the top and bottom line cropped. If I just did followed the Name Table instead of the screenshot, I would had been sucessful! At least on this part ;P

Quote from: tummai
At runtime when the debugger snapped, they have been bankswitched into the $87C0-$87FF address space.

Bankswitch. I didn't knew what it was until know. Well, the moment I looked at the debugger and it was snapping data from $87C0 and forward, I understood and fine. But, I've soon remembered that the ROM is usually big enough to need more than 4 bytes to write it's size: examples came to my mind when I opened Tile Molester and went to offset like 0001F312 and such. And then I though "Geez, this $87C0 can't be the actual address in the ROM where the data is being stored". And then I was left there, without knowing HOW to access this data, except, however, by doing a hex search for B1 E0 8D 07 20 C8 D0 F8, what would lead me to the place where the routine is being stored on the ROM. As the routine uses an indexed register, I wouldn't be able to modify my unwanted attribute table using this method.

Quote from: tummai
#2 is probably the easiest/fastest way.  BTW, If you try to edit the values in the Hex Editor without doing "Go Here In Rom File" first, it won't work.  Did you try to do that at first?

Now there's something useful. I've never used the built-in hex editor of FCEUX, as I didn't knew any applications for this. I just did knew that it wouldn't make any difference on the ROM if I just modified the values in hex editor while it was viewing the NES RAM. But now that you gave me this tip #2, I think I'll be able to finish this damned blinking effect. And of course, the knowledge I've got in this topic is imensurable. Smiley

Just one small question, it's not pertinent to my problem, but it would be nice to know one thing: each 2x2 area has a attribute byte assigned to it, right? I've noticed that, when emulating in PAL mode, we have 16x15 = 240 attribute tables, right? So it's supposed that, If I set a breakpoint for PPU $23C0 ~ $23FF, I would be able to set all these 240 attribute tables, but how, if I just have 64 bytes avaliable in this range? I mean, the loop that loads the attribute tables would run just 64 times, instead of the 240 times needed, isn't this right?
This part is still not clear in my mind. But in the meantime, I'm trying to get the modification done! Thanks so far!

EDIT - Oh, final consideration - tha data is being snapped from the offset 000147D0. I mean, it starts to be snapped from this offset on the ROM, going until 0001480F. I just need to figure out which of these bytes is the one referent to my problematic tiles, and then I think the info about 240 attribute tables and 64 addresses come into play Smiley
tummai
Guest
« Reply #8 on: August 14, 2009, 12:41:15 am »

Quote from: Knirt on August 13, 2009, 10:58:57 pm
Just one small question, it's not pertinent to my problem, but it would be nice to know one thing: each 2x2 area has a attribute byte assigned to it, right? I've noticed that, when emulating in PAL mode, we have 16x15 = 240 attribute tables, right? So it's supposed that, If I set a breakpoint for PPU $23C0 ~ $23FF, I would be able to set all these 240 attribute tables, but how, if I just have 64 bytes avaliable in this range? I mean, the loop that loads the attribute tables would run just 64 times, instead of the 240 times needed, isn't this right?
This part is still not clear in my mind. But in the meantime, I'm trying to get the modification done! Thanks so far!

It depends how you are counting.   Tiles on the NES are 8x8 pixels.  A mario block is 16x16 pixels (or 4 tiles).  An attribute byte assigns palette data to 2x2 mario blocks (equivalent to 4x4 tiles or 32x32 pixels).

The screen is made up of 256x240 pixels, which is the same as 32x30 tiles or 16x15 mario blocks.  An attribute byte assigns the palettes to 2x2 mario blocks, so to cover the whole screen you actually need 8x7.5 attribute bytes, (rounded up to 8x8 = 64).

Quote from: Knirt on August 13, 2009, 10:58:57 pm
EDIT - Oh, final consideration - tha data is being snapped from the offset 000147D0. I mean, it starts to be snapped from this offset on the ROM, going until 0001480F. I just need to figure out which of these bytes is the one referent to my problematic tiles, and then I think the info about 240 attribute tables and 64 addresses come into play Smiley

You found it Smiley  The routine is copying 64 attribute bytes from $147D0+ to PPU $23C0+.  They go in order, so the byte at $147D0 is for the very top-left 2x2 mario block area, the byte at $147D1 is for the block to the right of the first one, etc.

You know that there are 8 attribute bytes per row (8x8, see above).  Your blinkers look like they are at the end of the first row.  So maybe the 7th and 8th byte?  Do those bytes have a value of $00?

I think you've gotten it figured out.  Congrats!  Smiley  Attributes are one of the most difficult things to grasp on the NES.
Knirt
Guest
« Reply #9 on: August 14, 2009, 01:12:01 am »

Oh, so there is my confusion! I think I've understood completely how it works now, see if my logic is correct:



We can use one of this smaller blocks to determine which attribute byte is being sent into this block, but the same attribute byte that is being sent into this small block is, actually, being sent to the bigger block containing it. So the adjacent smaller blocks will also follow the same palette rule that was sent to the entire block. Sounds confusing, but in the overall, I think I understood. My mistake was to think that each small block would have an specific attribute byte, where, in the truth, is each big block that receives one attribute byte and applies it on all the smaller blocks contained on it. Thinking this way, is possible to fill the 240 2x2 tile areas with only 64 bytes, since they work on a 4x4 tile area.


And the final result. Thanks A LOT tummai, I'll be sure to write all this you teached me into a doc and present it to the Brazilian community, sooner or later. Some NES addicts that are friend of mine are already curious about what I'm studying, as they could use it on their translations or hacks. Spreading knowledge (and of course, mentioning your help in my translation Read me) will be my ways of repaying all you have done for me in this thread. Oh, the result!

tummai
Guest
« Reply #10 on: August 14, 2009, 07:59:33 am »

Quote from: Knirt on August 14, 2009, 01:12:01 am
Oh, so there is my confusion! I think I've understood completely how it works now, see if my logic is correct:



We can use one of this smaller blocks to determine which attribute byte is being sent into this block, but the same attribute byte that is being sent into this small block is, actually, being sent to the bigger block containing it. So the adjacent smaller blocks will also follow the same palette rule that was sent to the entire block. Sounds confusing, but in the overall, I think I understood. My mistake was to think that each small block would have an specific attribute byte, where, in the truth, is each big block that receives one attribute byte and applies it on all the smaller blocks contained on it. Thinking this way, is possible to fill the 240 2x2 tile areas with only 64 bytes, since they work on a 4x4 tile area.

Yes.  Each 32x32 pixel area (4 mario blocks) has one attribute byte that assigns palettes to that area.  The attribute byte is divided into four 2-bit values.  Each 2-bit value assigns a specific palette to a 16x16 mario block within the 32x32 pixel area.  It's really hard to explain clearly in words, but you've got it.

Quote
And the final result. Thanks A LOT tummai, I'll be sure to write all this you teached me into a doc and present it to the Brazilian community, sooner or later. Some NES addicts that are friend of mine are already curious about what I'm studying, as they could use it on their translations or hacks. Spreading knowledge (and of course, mentioning your help in my translation Read me) will be my ways of repaying all you have done for me in this thread. Oh, the result!



Sweet.  Looks good.  Glad I could help Smiley
Pages: [1]  


Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC