I have now extended my color switching solution to use a lookup table that has two entries, one for color and one for the next line skip value (HInt counter). I'll just show you some code, it's simple:
Code: Select all
typedef struct GradientEntry
{
u16 color;
u8 skip;
} GradientEntry;
void Gradient_start(GradientEntry * lut)
{
s_lut = lut;
s_index = 0;
*((vu32*)GFX_CTRL_PORT) = 0xc0000000;
*((vu16*)GFX_DATA_PORT) = s_lut[s_index].color;
VDP_setHIntCounter(s_lut[s_index].skip - 1);
s_index++;
}
void Gradient_setNextColor()
{
VDP_setHIntCounter(s_lut[s_index].skip - 1);
// prepare the palette 0 color 0 switch by writing the corresponding value to the VDP control port
*((vu32*)GFX_CTRL_PORT) = 0xc0000000;
u16 color = s_lut[s_index].color;
// wait until the HBlank becomes true _again_ (that is actually the next line after the one for which this interrupt was triggered)
while((*((vu16*)GFX_CTRL_PORT) & VDP_HBLANK_FLAG) == 0);
// now immediately write the color. the time is very short, and if we'd wait just a little too long we'd see the old color flickering in the next line
*((vu16*)GFX_DATA_PORT) = color;
s_index++;
}
And the test gradient I use:
Code: Select all
const GradientEntry defaultGradient[] =
{
{0, 20},
{0xffff, 40},
{0x7, 0xff}
};
But what happens instead:
Black 20 lines.
White 20 lines.
Red 40 lines.
Black for the rest of the screen.
Obviously the HInt counter is one off when called from HBlank. But I don't understand why. I'm very sure my code doesn't have an off-by-one error, so it's probably something hardware-related. Can somebody explain?
(The SEGA doc says "The horizontal interrupt is controlled by a line counter in register #10. If this line counter is changed at each interrupt, the desired spacing of interrupts may be achieved.", and that's what I'm trying to do)