Sol's Graphics Tutorial

09 - Distorted Transitions

Transitions are everywhere. They are the little, quick effects that move you from menus into the game action and they are used to restart the level whenever you die.

Like everything else, the transitions have to be coded. They add a little to the game, but a lot to the whole experience.

The transition we're implementing here is fairly simple. Basically we'll be moving the image and distorting it with a couple of sine curves. The main trick is to make the effect controllable.

Take a copy of the previous chapter as usual, resulting in ch09.

In the previous chapter we've loaded gPicture and gHeightmap, along with gPictureWidth and gPictureHeight. Let's transition between these two images.

Here's our new render() function;

void render(Uint64 aTicks)
{
  dist(((aTicks % 8000) / 4000.0f) - 1.0f);
}

The above line will call the dist() function with a floating point parameter randing from -1 to 1. One full cycle will take 8 seconds (4 seconds from -1 to 0, 4 seconds from 0 to 1).

Next, add this new function above render():

void dist(float v)
{
  int i, j;
  for (i = 0; i < gPictureHeight; i++)
  {
    for (j = 0; j < gPictureWidth; j++)
    {
      int u = j;
      int v = i;
      if (u >= 0 && u < gPictureWidth &&
          v >= 0 && v < gPictureHeight)
      {      
        gFrameBuffer[j + i * WINDOW_WIDTH] = 
          gPicture[u + v * gPictureWidth];
      }
      else
      {
        gFrameBuffer[j + i * WINDOW_WIDTH] =
          gHeightmap[j + i * gPictureWidth];
      }
    }
  }
}

Compile and run. You should now be seeing the picture in the top left corner of your window. If you have a crash, you probably have changed the window size to be too small.

First, let's move the picture vertically based on the parameter.

Add the following line in the beginning of the dist() function:

int ypos = (int)(-pow(v, 5) * gPictureHeight);

Here we calculate the fifth power of the v parameter. You can experiment with different values to see what happens. Basically what we achieve by this is that the image decelerates towards zero, and accelerates out from zero.

Change the int v = i; line inside the for loops to:

int v = i + ypos;

Compile and run. Note that if you try even powers (such as 2, 4, 6), you'll lose the negative values (since -1*-1 = 1) and the image will leave the same way as it arrived. Then again, maybe you want it that way.

Next, we'll distort the image as well. First, paste the following above the loops in the dist() function:

int xdist[WINDOW_WIDTH];
int ydist[WINDOW_HEIGHT];

for (int i = 0; i < WINDOW_WIDTH; i++)
{
  xdist[i] = (int)(sin((v * i) * 0.0324857) * v * 32);
}

for (int i = 0; i < WINDOW_HEIGHT; i++)
{
  ydist[i] = (int)(sin((v * i) * 0.0234557) * v * 32);
}

The 0.03.. values, like before, were entered more or less at random. Different values will give you slightly different effects.

The int u =.. and int v =.. lines change to:

int u = j + ydist[i];
int v = i + xdist[j] + ypos;

Compile and run again.

Now, we could stop here, but on the other hand, we could keep making the xdist and ydist tables more complex. With a bit of experimentation I ended up with this:

for (int i = 0; i < WINDOW_WIDTH; i++)
{
  xdist[i] = (int)((sin((v * (i + 10)) * 0.0024857) -
                    sin((v * (i + 23)) * 0.0324857) * 
                    sin((v * (i + 54)) * 0.0724857)) * pow(v, 3) * 32);
}

for (int i = 0; i < WINDOW_HEIGHT; i++)
{
  ydist[i] = (int)((sin((v * (i + 90)) * 0.0024857) -
                    sin((v * (i + 31)) * 0.0214857) * 
                    sin((v * (i + 57)) * 0.0514857)) * pow(v, 3) * 32);
}

I also changed the int u.. and int v.. lines to:

int u = j + ydist[i] + xdist[j];
int v = i + xdist[j] + ydist[i] + ypos;

Finally. to make sure that the transitions start or end cleanly with the second image, I changed the int ypos.. line to:

int ypos = (int)(-pow(v, 5) * (gPictureHeight + 64));

And that's basically it.

Additional things to try:

  • The xdist and ydist tables can contain just about anything. Go wild!
  • Experiment by only distorting u or v, but not both.
  • Change the render() function to transition image in, pause for a couple of seconds, and then transition out.
  • Load several images and perform transitions from one image to another.
  • Scale the result to the whole window.

Next up: 10 - Simple 3d Transformations..

Any comments etc. can be emailed to me.