Discussion about software development for the old-school Gameboys, ranging from the "Gray brick" to Gameboy Color
(Launched in 2008)
You are not logged in.
Hello. I am new to Gameboy development (still going through all the ASM tutorials) and I'm a little confused on how Game Boy Color palettes work.
So I've got this code (from this tutorial, though I'm not too good with Spanish). And it works. But... could someone please explain what it's doing, exactly?
call turn_off_LCD ; we call the routine to turn off the LCD ; To write the palette data ; Background tiles ld a,%10000000 ; First address(?) of the index, with autoincrement ld [rBGPI],a ld hl,BackgroundPalette ; The address of the background palette data ld b,4 ; Four colors (8 bytes) .background_palette_loop ld a,[hl] ld [rBGPD],a inc hl ld a,[hl] ld [rBGPD],a dec b jr z,.end_background_palette_loop inc hl jp .background_palette_loop .end_background_palette_loop ; . . . BackgroundPalette: DW $76BD, $753D, $14B4, $0019 EndBackgroundPalette:
Specifically, I don't understand what the "autoincrement" thing does exactly. I've read the Pan Docs, and it seems that what it's supposed to do is automatically increment rBGPD each time [rBGPD] is written to. But if that's the case, then wouldn't rBGPD ($FF69) become $FF6A after the first write? But that would seem to conflict with rOBPI (which is at address $FF6A).
I suppose what's really confusing me is that I'm not sure where the palette data is being copied to. rBGPD is a single byte, but, that doesn't make any sense. If I understand this correctly, there are 8 possible palettes (which would require not one byte but 64 bytes of data). Even a single color requires 2 bytes which can't possibly be located at rBGPD ($FF69). So where are these 64 bytes located?
Thanks in advance.
Last edited by h0tp3ngu1n (2019-08-18 14:57:50)
Offline
Those 64 bytes don't exist in normal memory, but in a separate memory space. You have to access them by first writing an address to $FF68 and then data to $FF69. So if you write 8 to $FF68 and then 0 to $FF69, you effectively write the value 0 to memory address 8.
Autoincrement works by incrementing the value of $FF68 after each write so you don't have to update $FF68 on each cycle if you're writing multiple bytes sequentially. For example, if you write $88 to $FF68, 0 to $FF69 and lastly $FF to $FF69, you will have written 0 to address 8 and $FF to address 9, and $FF69 is then ready to take a write to address 10.
Offline
Oh, I get it now. Thanks!
Offline
All right, I believe I've loaded the palettes correctly. And I see how to choose the palette to use for each sprite (you'd do that through the lowest three bits in the fourth byte in the OAM table, right?).
But how do I choose which palette to use for the background? (Sorry if this is a stupid question...)
Offline
The background doesn't have "a palette", rather there's a second map which holds attributes. Those include X and Y flip, the palette, and some more.
You can set these attributes per-tile.
Here is thee relevant section of the wiki: http://gbdev.gg8.se/wiki/articles/Video … de_only.29
Offline
Thanks, I guess I missed that part. But now I'm not sure how to write to the second map.
This is what I've tried so far (it's supposed to change all the tiles on the map to palette 0) but I'm probably doing it completely wrong:
; when the screen is turned off... ; switch to _SCRN0's second map ld a,VRB1 ld [rVRBS],a ; loop through all tiles on the tile map and assign palette 0 to each ld a,0 ; not priority | no vflip | no hflip | bank 0 | palette 0 ld hl,_SCRN0 ; ??? I think I'm supposed to be writing to bg tilemap memory (beginning at _SCRN0's address), but maybe not... ld bc,32*32 .loop ld [hli],a dec bc ld a,b or c jr nz,.loop .end_loop
Last edited by h0tp3ngu1n (2019-08-20 14:36:27)
Offline
Oh, never mind, I just got it working.
I'm really not sure what the problem was though. So if anybody could show me what I did wrong, it would help me out in learning this stuff. Thank you.
edit - Oh, now I see the problem. Very stupid mistake. The ld a,b inside the loop destroys the attributes (i.e. contained in register A). So only the first tile is changed correctly... and all the other attributes are replaced by garbage values.
Last edited by h0tp3ngu1n (2019-08-23 11:49:08)
Offline
Instead of `ld a, 0`, you should use `xor a`, which does the same but with 1 fewer byte and 1 fewer cycle
Offline