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.
Hi,
I tried to display more than 3 colors on a sprite by changing its OBJ palette by first waiting for a specific scanline and then during hblank changing one color entry of its palette.
This now results in the sprite flashing/cycling through the different colors instead of displaying more than 3.
Did I misunderstand how the hardware works? I thought once a line was drawn the color for this line is fixed, e.g. if Color 2 is blue on scanline 10, then I can set it to red on scanline 11 and it will not affect the blue on scanline 10.
But the behavior I'm seeing is instead that the color becomes red on both 10 and 11. Of course, if that's not how the hw behaves there could also still be a bug in my code.
If this does not work the other idea I had is changing the palette index in OAM between scanlines, but I guess if the former does not work this will also not work?
I know about sprite layering, but this would be too easy :')
Offline
Your understanding is generally correct. This sounds like a bug in your code. It might for example be the case that your code for updating the palettes is too slow so it doesn't finish within HBlank. Or you might not be writing to OBPI (the sprite palette index register) at any time during the frame so it keeps incrementing the index. (Assuming you're targeting GBC, and you set OBPI to auto increment mode at some point.) If you post your code I can try to figure it out.
Offline
Thanks for your reply and offer! I'm using gbdk-2020 and hacked together something using the metasprites example as a base, with your input I figure the problem is that my approach is too slow in C: first I wait for a scanline with LYC and then inside I enable the hblank interrupt.
The hblank correclty performs the palette update and then sets the new LYC, but if by now the Gameboy is already past this LY this would result in waiting a frame and color cycling....I have not thoroughly debugged it yet myself and would like to do so before I bother you with it
EDIT:
Yes that was indeed the problem, my previous code was just too slow (so LYC interrupt to then trigger hblank interrupt is a bad idea).
I now changed the program to only use the hblank interrupt and it works as expected.
Inside the hblank I added a check for LY==LYC using the STAT register.
Code snippet for those interested (I used a custom 16x32 sprite placed in the top left corner, so the colors are hardcoded for it):
uint8_t recolor_i = 0; //to change color on scanlines {1, 5, 15, 24, 27}, off-by-one(?) const uint8_t recolor_lines[] = {0, 4, 14, 23, 26}; // brown, skin, blue, red, brown const uint16_t rgb555_data[] = {RGB8(175,95,47), RGB8(255, 219, 182), RGB8(36,109,219), RGB8(217, 38, 41), RGB8(175,95,47)}; const uint8_t pal_idx[] = {2, 1, 2, 1, 2}; // palette idx to change void hblank_isr() { if (STAT_REG & STATF_LYCF) { set_sprite_palette_entry(0, pal_idx[recolor_i], rgb555_data[recolor_i]); recolor_i++ ; if (recolor_i == 5) {recolor_i = 0;} LYC_REG = recolor_lines[recolor_i]; } } int main() { // ... CRITICAL { if (_cpu == CGB_TYPE) { cpu_fast(); set_default_palette(); LYC_REG = recolor_lines[recolor_i]; STAT_REG |= STATF_MODE00; add_LCD(hblank_isr); add_VBL(vblank_isr); enabled_isr = LCD_IFLAG|VBL_IFLAG; set_interrupts(enabled_isr); } else { // DMG... } } }
Last edited by clouds (2022-05-16 08:25:09)
Offline
you don't need such tricks, you may simply overlay one hardware sprite with one palette over the other hardware sprite with the other palette. you may compose a metasprite with such an overlaying. you may do that on the DMG as well, because it has two object palettes, that is a common practice.
Offline
But then I would need to store two copies of the overlay sprite in tile RAM also right? (because if it's the same just the top one would be displayed).
I agree that sprite overlaying would generally be the better choice and with the approach I posted above you can't easily use LYC for other purposes.
I mostly tried this because I wanted to get a better understanding how the drawing works.
Offline