How change pallete of one part in nametable [C+Shiru neslib]

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
Axi0maT
Posts: 12
Joined: Mon Aug 24, 2015 10:26 pm
Location: Koszalin, Poland

How change pallete of one part in nametable [C+Shiru neslib]

Post by Axi0maT »

Hi

I have question as in Subject - how change pallette of one part (2x2 tile) in Nametable?

my example:
In selected part of nametable I have set palette at number 1 on background:
Image

Later in game I want shot&destroy a block and remove him from game... I update tile but I must change palette to 2 (arrow on upper image) - set cave element:
Image

And here is the problem - how can I make this? I don't have any idea... Anybody can help me? I use CC65 (C) and Shiru nes lib, but any help (asm too) would be greatly appreciated.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: How change pallete of one part in nametable [C+Shiru nes

Post by rainwarrior »

Maybe this Wiki article can help: http://wiki.nesdev.com/w/index.php/PPU_attribute_tables

You need to determine two things:

1. Which byte the tile's attribute is in.
2. Which 2 bits of that byte correspond to that tile.

In the screen tool, this information is actually called "AtrOff" in the status bar at the bottom.

Once you figure that out, just change those two bits, and submit the new byte to be changed in the next NMI update.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: How change pallete of one part in nametable [C+Shiru nes

Post by tokumaru »

You do it the same way you did with the tiles, but instead of changing the name table you change its corresponding attribute table. I assume you're calculating the address of the tiles to change using a formula like this: NTAddress + tileY * 32 + tileX

In order to change attribute table you need a different formula, as well as a couple of bit masks. The masks are necessary because a single byte holds palette information for 4 16x16-pixel blocks, so if you want to modify only one, you have to manipulate only the bits related to the block you're changing, and for that you need to perform bitwise operations using bit masks.

The following formula will give you the address of the byte you need to change: ATAddress + (tileY / 4) * 8 + (tileX / 4)

Now that you know where to get the byte from, you need to create two bit maks: one for clearing the bits related to the block you're changing in the attribute byte, and the other to create a byte containing the new palette index only at the position that corresponds to the block being changed. These masks are the inverse of each other.

There are 4 possible pairs of bit masks, since each attribute byte holds data for 4 blocks. To know which of the 4 blocks you have to modify, you have to use the tile coordinates again. The lower bit is useless, because attributes can't be applied to 8x8 pixel areas, so you get the second bit of each coordinate and create an index (a number between 0 and 3) that will tell you which of the 4 pairs of masks to use:

block = (TileY & 0x02) | ((TileX & 0x02) >> 1)

Then, depending on the result, you're going to use one of these 4 pairs of masks (one from the top row and the one below it):

%11111100, %11110011, %11001111 or %00111111 (make room for the new bits in the attribute byte)
%00000011, %00001100, %00110000 or %11000000 (make sure the new bits are in the correct position)

The masks in the top row are used to clear the bits that affect the block you're changing, so you can later put the new bits there. The masks in the bottom row are used to make sure the new palette index stays in the correct place to affect only the block you're changing, leaving the others alone. The whole process goes like this:

1 - calculate the AT address;
2 - calculate the block index and generate a pair of masks from it (loading from a table or using IFs, for example);
3 - AND the bottom mask with a byte containing the new palette index 4 times (e.g. %01010101 for palette 1, %10101010 for palette 2, etc.) to keep only the bits that are in the correct position;

Then, during vblank:

4 - read the attribute byte from the attribute table;
5 - AND it with the top mask to make room for the new attribute bits;
6 - OR it with the byte that contains the new bits;
7 - write the result back to the attribute table;

This is mostly about the math, which is the same whether you're using C or assembly. So if you know how to manipulate VRAM already (which you probably do, since you're modifying the name table), you can surely manipulate the attribute table the way I described above.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: How change pallete of one part in nametable [C+Shiru nes

Post by rainwarrior »

tokumaru wrote:4 - read the attribute byte from the attribute table;
A lot of games store a copy of the attribute table in RAM to avoid having to read it back from VRAM during vblank.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: How change pallete of one part in nametable [C+Shiru nes

Post by tokumaru »

I do that. I intentionally avoided mentioning that here because things were already sounding complex enough. :?

I figured that reading-modifying-writing in this case wouldn't be such a big issue, since this appears to be a non-scrolling game, and there's likely not much work being done during vblank.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: How change pallete of one part in nametable [C+Shiru nes

Post by rainwarrior »

OP is using shiru's library in C; I don't think it has that capability in its existing vblank routine.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: How change pallete of one part in nametable [C+Shiru nes

Post by tokumaru »

I see... well, if customizing the vblank routine isn't an option, there's no other way than to keep a copy of the attribute tables in RAM. I actually think that way is better, if you have the RAM to spare. If there's no scrolling, only 64 bytes will do, so it's probably not such a big issue.
User avatar
Axi0maT
Posts: 12
Joined: Mon Aug 24, 2015 10:26 pm
Location: Koszalin, Poland

Re: How change pallete of one part in nametable [C+Shiru nes

Post by Axi0maT »

Thanks for reply, but maybe I was bad clarify the problem
My problem is not what (what change) and where (where change)... but HOW? Probably because I assume that however well I calculate values and address.

So again :) This time maybe with numbers.
rainwarrior wrote:Maybe this Wiki article can help: http://wiki.nesdev.com/w/index.php/PPU_attribute_tables
I know this tutorial - I used it once to calculate position and values. But as you said everything is calculated in NES Screen Tool.

Image

adress is: $23F3 (on screen up as $3F3 - well, maybe here I do something bad?)
values is: 1<<0 | 2<<2 | 1<<4 | 2<<6 = 153 = 0x99 (here - everythings is ok - NES Screen Tool said the same -> screen up)
I must change to: 2<<0 | 2<<2 | 1<<4 |2<<6 = 154 = 0x9A (yeah Screen Tool calculate it for me to)

Now HOW?
I try this:
ADDR(0x23F3) = 0x9A;
and this:
SET_RESISTER(0x23F3, 0x9A);

but nothing happens :evil:

Maybe I do this in not right place?
before or after? ppu_wait_nmi();
or
before or after? ppu_wait_frame();

Any suggestion?

PS: Yes, this is one screen game... without scrolling
Last edited by Axi0maT on Fri Oct 02, 2015 11:16 pm, edited 2 times in total.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: How change pallete of one part in nametable [C+Shiru nes

Post by rainwarrior »

So the question is really how to do VRAM updates with Shiru's library?
neslib.h wrote:

Code: Select all

//when display is enabled, vram access could only be done with this vram update system
//the function sets a pointer to the update buffer that contains data and addresses
//in a special format. It allows to write non-sequental bytes, as well as horizontal or
//vertical nametable sequences.
//buffer pointer could be changed during rendering, but it only takes effect on a new frame
//number of transferred bytes is limited by vblank time
//to disable updates, call this function with NULL pointer

//the update data format:
// MSB, LSB, byte for a non-sequental write
// MSB|NT_UPD_HORZ, LSB, LEN, [bytes] for a horizontal sequence
// MSB|NT_UPD_VERT, LSB, LEN, [bytes] for a vertical sequence
// NT_UPD_EOF to mark end of the buffer

//length of this data should be under 256 bytes

void __fastcall__ set_vram_update(unsigned char *buf);
So, after reading this, I think the code to update a single byte in the next vblank would look something like:

Code: Select all

unsigned char update_buffer[5];

attribute_address = 0x23F3; // PPU address of byte to write
attribute_value = 0x35; // actual value of byte to write

// create VRAM update buffer for neslib
update_buffer[0] = (attribute_address >> 8) | NT_UPD_HORZ; // MSB of address + control bit for direction
update_buffer[1] = attribute_address & 0xFF; // LSB of address
update_buffer[2] = 1; // length of data to write (1 byte)
update_buffer[3] = attribute_value;
update_buffer[4] = NT_UPD_EOF;

set_vram_update(update_buffer); // give the update buffer to neslib to apply at next vblank
ppu_wait_nmi(); // wait for the next frame so the changes will be applied
set_vram_update(NULL); // disable the update so it doesn't keep re-using the buffer every frame.

You can probably search shiru's example programs for "set_vram_update" to find other examples of how to use this.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: How change pallete of one part in nametable [C+Shiru nes

Post by tokumaru »

Didn't you say in your original message that you were able to change the tiles but not the palette? Now I'm confused!
User avatar
Axi0maT
Posts: 12
Joined: Mon Aug 24, 2015 10:26 pm
Location: Koszalin, Poland

Re: How change pallete of one part in nametable [C+Shiru nes

Post by Axi0maT »

rainwarrior wrote:So, after reading this, I think the code to update a single byte in the next vblank would look something like:

Code: Select all

unsigned char update_buffer[5];

attribute_address = 0x23F3; // PPU address of byte to write
attribute_value = 0x35; // actual value of byte to write

// create VRAM update buffer for neslib
update_buffer[0] = (attribute_address >> 8) | NT_UPD_HORZ; // MSB of address + control bit for direction
update_buffer[1] = attribute_address & 0xFF; // LSB of address
update_buffer[2] = 1; // length of data to write (1 byte)
update_buffer[3] = attribute_value;
update_buffer[4] = NT_UPD_EOF;

set_vram_update(update_buffer); // give the update buffer to neslib to apply at next vblank
ppu_wait_nmi(); // wait for the next frame so the changes will be applied
set_vram_update(NULL); // disable the update so it doesn't keep re-using the buffer every frame.
And this is exactly what I need. Thank You sooooooo much :)
Previously, I've used already set_vram_update but to update tiles on background (namestable), but I did not know that the attributes can also be added to set_vram_update.
rainwarrior wrote:You can probably search shiru's example programs for "set_vram_update" to find other examples of how to use this.
Some examples are very modestly described and often do not explain how the use of certain elements.
tokumaru wrote:Didn't you say in your original message that you were able to change the tiles but not the palette? Now I'm confused!
Yeah, so I was updating tiles on the background but did not know how to change the colors selected segments. Code of rainwarrior do all what I need. :)
Post Reply