Sol's Graphics for Beginners

(ch19.cpp)

(prebuilt win32 exe)

19 - 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 that we'll be building here doesn't contain much new if you've followed the last couple of chapters. 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, so we can apply it into the game.

We'll start from the chapter 17 skeleton again, and you'll need this picture (right-click, save as) as well.

First, let's load the image. Add this to the beginning of the file, after the screen surface:

// Picture surface
SDL_Surface *gPicture;

and the loading code in init()..

SDL_Surface *temp = SDL_LoadBMP("picture19.bmp");
gPicture = SDL_ConvertSurface(temp, gScreen->format, SDL_SWSURFACE);
SDL_FreeSurface(temp);

Find the 'rendering here' comment in render() and add the following after it:

dist(((tick % 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)
{
  if (SDL_MUSTLOCK(gPicture))
    if (SDL_LockSurface(gPicture) < 0) 
      return;

  int i, j;
  for (i = 0; i < HEIGHT; i++)
  {
    for (j = 0; j < WIDTH; j++)
    {
      int u = j;
      int v = i;
      if (u >= 0 && u < WIDTH &&
          v >= 0 && v < HEIGHT)
      {      
        ((unsigned int*)gScreen->pixels)[(j) + (i) * PITCH] = 
          ((unsigned int*)gPicture->pixels)[(u) + (v) * (gPicture->pitch / 4)];
      }
      else
      {
        ((unsigned int*)gScreen->pixels)[(j) + (i) * PITCH] = 0;
      }
    }
  }

  if (SDL_MUSTLOCK(gPicture)) 
    SDL_UnlockSurface(gPicture);
}

Compile and run. You should now be seeing the little mockup picture I put together in photoshop.

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

Add the following line in the dist() function after we lock the gPicture surface:

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

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, but after the definition of the i and j integers:

int xdist[WIDTH];
int ydist[HEIGHT];

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

for (i = 0; i < 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 (i = 0; i < 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 (i = 0; i < 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 with a black screen, I changed the 'int ypos..' line to:

int ypos = (int)(-pow(v, 5) * (HEIGHT + 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 main 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.
  • Instead of filling the "background" with black color, display another image under the one transitioning in/out.

Next up we'll have a very small detour to the 3d world in the form of 20 - Simple 3d Transformations..

Having problems? Improvement ideas? Just want to discuss this tutorial? Try the forums!

Any comments etc. can be emailed to me.