Well, I've been trying to make a code that looks for an object's palette bits based on what each palette is. I've made a 64 byte "palette table" in ram where the first 32 bytes contain individual numbers that correspond to different palettes and where the second 32 bytes say how many objects are currently using the palette. In the code, it first looks at the first 32 bytes to see if any of the existing palettes match the one you are trying to add, and if none of them do, you go to the last 32 bytes that if 0, you can create a new palette in the area in the first 32 bytes that corresponds to the last 32 bytes and also add 1 to the spot you found the empty palette slot in in the last 32 bytes to say that the slot is being occupied. I think I commented pretty good, but If you're unsure about something or just don't get it, you can ask me to better explain. There are a few thing's I'm not sure about that I commented on, and if you have a really good idea for a better way to check for palettes, you can also say that.

This code is for ca65, but I'm sure you can understand it if you don't have it.

Code:

.proc start_palette_checker rep #$30 ; A=16, X/Y=16 ldx #$0000

palette_checker_loop1: lda PaletteTable,x ;first 32 bytes specify what palette is in the palette slot cmp PaletteRequest ;sees if the color in the palette slot matches with the one you are trying to add bne prepare_for_palette_checker_loop

done: lda PaletteTable+32,x ;the last 32 bytes say how many objects are using that palette inc ;so if it is 0, it is safe to overwrite it. a new object is using that palette, sta PaletteTable+32,x ;so increase it by 1.

sep #$20

ldx ora Attributes+1 ;this will be direct paged for object slots, I just forgot how to do it without having to do a:. sta Attributes+1 ;Attributes is the exact same thing as bytes 3 and 4 in oam. rts

prepare_for_palette_checker_loop: inx ;we're using 16 bits, so you increase x by 2. inx cpx #$0020 ;sees if we're at the second half of the palette table. bcc palette_checker_loop1

palette_checker_loop2: lda PaletteTable,x bne prepare_for_palette_checker_loop ;0 means that no objects are using the palette slot, ;so it is safe to overwrite it.

done2: ldx ror ;same thing as dividing by 2? How is asl any different than rol then? ora Attributes+1 ;this will be direct paged for object slots. sta Attributes+1 ;Attributes is the exact same thing as bytes 3 and 4 in oam.

lda PaletteRequest sta PaletteTable-32,x ;remember, x is twice as much here as it would be in done1 (64/2 = 32) lda PaletteTable,x ;the last 32 bytes say how many objects are using that palette inc ;so if it is 0, it is safe to overwrite it. a new object is using that palette, sta PaletteTable,x ;so increase it by 1.

sep #$20 ;how do you get an 8 bit x, because I'm pretty sure that's what you need here ldx ;(by the way, this next section is going to be pretty rough, because I've never directly worked with DMA...) asl ;since a palette is 32 bytes and we already have the palette number times 4, asl ;we multiply it by 8 for the result. asl asl stx $2121 ;says which color to start at

You know, I just realized something. If I have about 20 bullets that are the exact same (including color) onscreen, then you just lost a good deal of time doing the exact same thing over again. Do you think you could have it to where a table of registers hold a value for how many objects are using that palette, and where the palette is in the palette table? You would have something like 2 registers (4 in 16 bit) for an explosion color, where the first says how many objects are using the palette, and another that has where the palette is in the palette table. If the first register is 0 and you are adding a new object that uses that palette, you look at the palette table for a an open spot. the 2nd register in the explosion palette registers would be set exactly like the palette bits in oam, (These: %00001110) so you only need to convert the number once.

This is going to be a last resort right? Doing dynamic animation on individual sprites, and organizing them into screen/vram regions, while making sure the metasprite animates as a whole while keeping track of dma usage, and having the ability to sync up explosion sprites, except when it can't due to screen/vram regions is complicated enough without adding color palettes to the mix.

I would personally think most games would favor a mixed approach - reserve a few palettes for objects that will be on screen always or frequently (like bullets), and then swap out the rest as needed. That or plan ahead through smart level design to just not overflow your palette space by segregating certain types of enemies, so you can just load the whole block of palettes and update it as needed when you approach different sets of enemies

My gut feeling is this approach may be a bit more processing than it's worth at the SNES level.

I'm actually not going to do that, but I thought it would have been a cool idea, but yeah, maybe I'm being a bit over ambitious. I haven't run into slowdown yet, but I really haven't done much of anything. I wonder how much I should be worrying... (I'm most definitely going to use fast rom, but I don't know how much it would help.)

Khaz wrote:

I would personally think most games would favor a mixed approach - reserve a few palettes for objects that will be on screen always or frequently

Yeah, that's true. I think I'll reserve palettes for player 1 and 2, so at least that's a little less to worry about.

Does anyone know how DKC handles changing palettes? It seems pretty accurate and it definitely isn't hardcoded to switch palettes halfway through the level or anything. One weird thing about how DKC handles palettes is that if there are too many objects with unique palettes on screen, the game will sometimes mess up the hud and banana palette for an enemy, and it will stay messed up even when all the objects disappear. I would have thought they would make it to where it checks if all the palettes are used up and just doesn't write anything then, (meaning it doesn't write over palette 1) but I guess not.

Does anyone know how DKC handles changing palettes? It seems pretty accurate and it definitely isn't hardcoded to switch palettes halfway through the level or anything. One weird thing about how DKC handles palettes is that if there are too many objects with unique palettes on screen, the game will sometimes mess up the hud and banana palette for an enemy, and it will stay messed up even when all the objects disappear. I would have thought they would make it to where it checks if all the palettes are used up and just doesn't write anything then, (meaning it doesn't write over palette 1) but I guess not.

I too would be thrilled to hear more about how official games handled this particular issue.

I'm actually not going to do that, but I thought it would have been a cool idea, but yeah, maybe I'm being a bit over ambitious. I haven't run into slowdown yet, but I really haven't done much of anything. I wonder how much I should be worrying... (I'm most definitely going to use fast rom, but I don't know how much it would help.)

That simplifies it a lot. Metasprites would only need to be updated as a whole, instead of checking for each and every sprite. The screen/vram region thing sounds like it could be taxing on the CPU, I don't know how much though. I would only go that route if I absolutely need to.

The thing about the color palette doesn't sound CPU taxing at all. There are only 8 palettes to look at a time.

Some things to fix in your code:- the whole thing can just be done in 8-bit mode, since your dealing with just 8-bit numbers- there are 8 palettes, not 32 palettes- replace "ldx" with "txa"- palette value starts at bit-9 of the attributes word, so you need an "asl" before storing to "attributes+1"- replace "ror" with "and #$03"- DMA should be done in another routine, during vblank

Well, I actually got around to trying to make it to where I have a giant table in ram that has information for all the object palettes that are going to be used in the game, (Each slot in the table consists of 2 bytes: one that says where the palette is in cgram, and one that says how many objects are using that palette. When the second number is 0, you remove the palette from cgram.) and I have the table that sees which of the 8 onscreen sprite palettes are occupied. Because the DMA routine needs to be during vblank, I made another table which has the addresses of any new palettes. (By the way, the address cannot be 0. Otherwise, the code thinks that there is no palette and quits.) I'm feeling rather lazy right now, so nothing is commented, but I can change that latter. (Oh yeah, one thing, how do you get both an 8 bit accumulator and index registers?)

and it showed the correct palette in the palette 0 (for sprites). I then wrote

Code:

ldy #$00 jsr start_palette_checker ldy #$02 jsr start_palette_checker

and it also worked, having the second palette going to palette 1 because the first one was already occupied. Next, I copied this about 12 times or something and even though that is too many palettes for the SNES to handle for sprites, it didn't seem to mess anything up and instead just refused to try to load the palettes, like I want it to. I haven't linked the code with any of the objects yet, but I doubt it will do anything unexpected. Anyway, I have the code made, and I feel like sharing it, do feel free to use it. I can answer questions if anyone has any.

Umm I don't want to sound like a smarty-pants, but I think you kinda forgot to loop back to palette_checker_loop. Running your code in my head, the first time it executes it branches to done. The second time it falls into done with X = 1, because there is no loop.

I trust you when you said it works, did you submit the wrong code?

Also, you appear to be preforming a 16 bit check on OnscreenPaletteTable, even though it appears to use 8 bit values. This will cause problems when slot 2 is clear, but slot 3 is allocated.

Espozo wrote:

Well, I actually got around to trying to make it to where I have a giant table in ram that has information for all the object palettes that are going to be used in the game

You appear to have TotalPalettesTable inside shadow RAM. I'm not sure how big it is, but I guess it would be 2*Number of Palettes and could easily grow to 256 bytes. Shadow RAM is precious, you only have ~7.5KiB of the stuff to play with.

May I recommend you move TotalPalettesTable to WRAM bank $7E or $7F and access it through long, X addressing. There would be some overhead, but as the start_palette_checker/palette_cleanup routines would only be called on object spawn and destroy it is well worth the RAM savings.

but I think you kinda forgot to loop back to palette_checker_loop. Running your code in my head, the first time it executes it branches to done. The second time it falls into done with X = 1, because there is no loop. I trust you when you said it works, did you submit the wrong code?

No, that was the one I used, and I even assembled the game just now using it. (I'm really not even sure how it worked.)

UnDisbeliever wrote:

Also, you appear to be preforming a 16 bit check on OnscreenPaletteTable, even though it appears to use 8 bit values. This will cause problems when slot 2 is clear, but slot 3 is allocated.

Where? I'm pretty sure the only place where I check onscreen palette table is here, and the accumulator is set to 8 bit.

Code:

.proc start_palette_checker rep #$30 sep #$10 ldx #$00

palette_checker_loop: lda OnscreenPaletteTable,x beq done

Quote:

You appear to have TotalPalettesTable inside shadow RAM. I'm not sure how big it is, but I guess it would be 2*Number of Palettes and could easily grow to 256 bytes. Shadow RAM is precious, you only have ~7.5KiB of the stuff to play with.

May I recommend you move TotalPalettesTable to WRAM bank $7E or $7F and access it through long, X addressing. There would be some overhead, but as the start_palette_checker/palette_cleanup routines would only be called on object spawn and destroy it is well worth the RAM savings.

You're probably going to hate me for saying this, but what exactly is shadow ram?

It contains the first 8KiB of WRAM and is the area Direct Page and the Stack are processed in. I usually allocate 512 bytes at $1E01-$1FFF for the stack leaving me with 7.5KiB to play with.

My god man what do you DO to your stack? I mean I have a mostly-functional game on my hands at this point and I don't think my stack ever gets lower than about $1FD0ish. I try to avoid using it at all except to preserve registers and occasionally quickly store a value I'm going to use again in a second...

Who is online

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum