fredag 20. juni 2014

[ SDL2 - Part 8 ] It's TIME for another update!


In the last tutorial we learnt how to load and render png files with alpha layers. This time we're gonna dive into rotating textures. Or more presicely ; rendering them rotated.

Today e'll be making a simple, but working, analog clock.  This will show how to rotate textures in SDL2. We'll also improve how we represent textures


Until now, we have been rendering using SDL_RencerCopy. But in order to rotate, we need a different function ;  int SDL_RenderCopyEx it takes a couple more arguments. I'll try to explain all of them.

   SDL_Renderer* renderer,
   SDL_Texture* texture,
   const SDL_Rect* srcrect,
   const SDL_Rect* dstrect
   const double angle,
   const SDL_Point* center,
   const SDL_RendererFlip flip

  • renderer - the SDL_Renderer we always use for rendering
  • texture  - the SDL_Texture we want to render
  • srcrect  - which part of the SDL_Texture to render. null for everything.
  • dstrect  - where to render it. Used exactly like in SDL_RenderFillRect)
  • angle     - angle of rotation
  • center    - the center of rotation
  • flip      - flipping of texture ( vertical, horizontal, no flip )
Return value
  • 0 on success

As you can see, the first four parameters are identical to SDL_RenderCopy you can read more about them in part 6.

Texture flip

Texture flip is represented as an SDL_TextureFlip

It is simply an enum with the following three values :
  • SDL_FLIP_NONE              - don't flip at all
  • SDL_FLIP_HORIZONTAL   - flip horizontaly
  • SDL_FLIP_VERTICAL         - flip vertically

For now, we will just be using SDL_FLIP_NONE.

Center of rotation

The center of rotation is given as a position seen from the top-left of the texture ( remember; in SDL 0,0 is the top-left of a texture. ) So a center of 0,0 will mean you rotate it from the top-left corner.

Finding the center of rotation is usualy quite simple, it'll usually just be the center of the texture you are using. For a circle, like a spinning wheel, the center of rotation will simply be the center of the wheel. Or for a Tetris piece it will be the center of the retris piece. The center of a texture is easy to find. Since a center of any rectangle will be halfway along its x axis and halfway along its y axis, the position can be calculate as follows ;

// The rect of the texure.
// Assume it is filled out with pos(x, y) and size( w, h )
SDL_Rect textureRect;
SDL_Point center;

// Calculate center pos by setting
// ->x pos to half of witdh
// ->y pos to half of height
center.x = textureRect.w / 2;
center.y = textureRect.h / 2;

The type of center is one we haven't used before, SDL_Point. But an SDL_Point is simply just a struct with an x and y value.

In our case we are going to make a working analog wall clock. So we can't rotate it around the middle ( that would be a weird clock! ) What we need to do, is find the base of the hands.

Here is a picture of on our clock hands. The white hole in the middle is where we want the center of rotation to be. All three hands look very similar to this, all hands have a hole in the base, and all of them rotate around that point.

If you look closely at the green dots, you'll see that the distance to the hole from either of the sides and the bottom is all the same ( three green dots. ) The green dots span the entire width of the base. So to find the center x value, we simply take half of the width. Looking at the picture, you'll see that the distance from the bottom to the hole is the same as the distance from the sides subtract half of the width to find the y position of the hole.

So the code for finding the center of rotation will be something like this :

// Assume textureRect is filled out with pos and size
SDL_Rect textureRect;
SDL_Point textureCenter;

int halfWidth = textureRect.w / 2;
textureCenter.x = halfWidth;

// Center.y  = half of the width above texture bottom.
textureCenter.y = textureRect.h - halfWidth;

Putting things together

Previously we have worked with simply storing the SDL_Texture and SDL_Rect as separate objects in our main.cpp. But now we also need to store the center of rotation and the angle. So that's four variables for each texture. With so many variables, it's a good idea to split it into a separate struct :

We also need to change main to make the clock work

As you can see, there is very little code needed in main since a lot of it is moved into Texture.h


The full code can be downloaded here.

Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

For a full list of my tutorials / posts, click here.

Ingen kommentarer:

Legg inn en kommentar