SGDK. Stretch/Compress the picture.

Preface.

Sega Megadrive, unlike the SNES, does not know how to enlarge the image at the level of iron. However, using interrupts, you can stretch the picture, or vice versa to compress. To understand how it works, you need to understand how the image was drawn on TVs before.

How images are drawn on old TVs.

Old TVs used a kinescope (cathode ray tube), inside of which, an electron gun, fires an electric beam at the phosphor, which lights up, thereby illuminating the pixel on the screen.

Next, this beam passes through all the pixels, drawing pixels, line by line. And, as soon as the beam has drawn the screen, it returns to the starting position, and repeats the process. This is how the image is drawn.

There are time intervals HBLANK and VBLANK:

  • HBLANK – the time of movement of the beam, from the end of the current line, to the beginning of the next.
  • VBLANK – the time for which the beam will return from the end point of the screen to the start .

VLANK time is longer than HBLANK, due to the difference in distance.

But, what about SGDK?

You can move the plain (layer) in HBLANK time, yes, right during the render. If you scroll through the plain, during rendering, you can stretch it or vice versa, compress image.

Write the code.

As the basis of the SGDK project, I took the project from SGDK. Create an image.

Open main.c and replace the main function with following:

int main()
{
	VDP_drawImage(BG_A, &img, 0, 0);

VDP_setScrollingMode(HSCROLL_PLANE, VSCROLL_PLANE);
    VDP_setPaletteColors(0, palette_black, 64);

SYS_disableInts();
    {
        VDP_setHIntCounter(0);
        VDP_setHInterrupt(1);
        SYS_setHIntCallback(HIntHandler);
        SYS_setVIntCallback(VIntHandler);
    }
    SYS_enableInts();
    PAL_fadeIn(0, 15, img.palette->data, 32, FALSE);

while (TRUE)
    {
        SYS_doVBlankProcess();
    }
}

Let’s analyze the new lines:

SYS_disableInts();
{
  VDP_setHIntCounter(0);
  VDP_setHInterrupt(1);
  SYS_setHIntCallback(HIntHandler);
  SYS_setVIntCallback(VIntHandler);
}
SYS_enableInts();
  • SYS_disableInts disable interrupts, if this is not done, VDP calls will be spoiled.
  • VDP_setHIntCounter – specify how many lines, an interrupt is called, 0 means every line, 4 means every 5th line.
  • VDP_setHInterrupt – include horizontal (HBLANK) interrupts.
  • SYS_setHIntCallback – specify the function that will be called during the HBLANK interrupt.
  • SYS_setVIntCallback – define the function, which is called, during the VBLANK interrupt.
  • SYS_enableIntsInterrupts are configured, can be enabled.

Everything else, I said in SGDK. Fade-in and Fade-out transitions, as well as in SGDK. Layer, tile, line.

Now, add the following lines somewhere at the beginning of the script:

u16 cur_line = 0; //current line
f16 v_offset = 0; //shif of the plane
f16 v_scroll_step = FIX16(3); //step to increase the displacement of the v_offset

void HIntHandler()
{
    VDP_setVerticalScroll(BG_A, cur_line+fix16ToInt(v_offset)); //move the plane vertically relative to the cur_line
    v_offset -= v_scroll_step; //change the displacement
   
}

void VIntHandler()
{
    //the frame is drawn, so
    v_scroll_step = FIX16(3.0); //You need to reset the step. Will be needed later
    v_offset = 0; //and remove the shift of the play relative to the current line.
 }

I explained all the code in the comments. Now, run.

As you can see, the picture is compressed, and turned over.

The picture flipped because we moving the plain up.

VDP_setVerticalScroll(BG_A, cur_line+fix16ToInt(v_offset));

v_offset – will go minus.

Thus, the current line goes down, and the plain goes up, so you get an inverted image.

Let’s complicate the example by adding the improved HIntHandler and VIntHandler functions.

void HIntHandler()
{
    VDP_setVerticalScroll(BG_A, cur_line+fix16ToInt(v_offset));
    v_scroll_step += FIX16(0.02); //Change the step, thereby, the speed of the plane - increases
    v_offset -= v_scroll_step;
}

void VIntHandler()
{
    cur_line += 1; //move the current line, each frame
    v_scroll_step = FIX16(3.0); //Reset the step with which the plain moves.
    v_offset = 0; 
 }

Again, the explanation in the comments.

Now, compile and run.

You can see that the lower the image, the smaller it is. What they wrote, they got.

Conclusion.

Horizontal interrupts allow you to achieve beautiful effects on the Sega Megadrive, which can not but rejoice. Also, in the folder C/SGDK/sample/fxh-int, there are 2 examples (from which I learned) scaling and wobble. Having studied which, you will be able to better understand this topic.

Final result.

Пожалуйста отключи блокировщик рекламы, или внеси сайт в белый список!

Please disable your adblocker or whitelist this site!