Using SDL2: Moving an image
Tags: c, cpp, sdl, classes
Published: 2018-10-30 19:18:43

Before we start this next part, we need to have a little talk about resource management in SDL2. As you know, SDL2 is a C library. This means it heavily relies on pointers and passing pointers around. Typically in C, when a function returns a pointer, it usually means there was something dynamically allocated and the pointer to it was returned back to you. There is no automatic clean up in C. Everything is manually done including resource management.

**And what's your point?**

What I'm trying to get at is we've been leaking memory all this time.

***Gasp!* What?! And you've never told this to us? How could you!**

I know, I know. We didn't free the resources because the programs were short-lived and it would have cluttered the code. And besides, we weren't technically leaking memory since it was claimed back by the OS after our window closed.

**Sorry about overreacting.**

Apology accepted. Now with that over with, let's do some clean up first.

We can't put everything in the `main()` function so we'll have to break up the code into different sections. You can use functions, however, since I'm using C++ I'll be using classes.

I'll be creating a class called `Application` and, for now, will have two methods:

1. `update()`
2. `draw()`

The method `update()` will handle any events and draw to the back buffer.
`draw()` will simply call `SDL_UpdateWindowSurface()` to show the back buffer.

main.cpp:

```cpp
#include <iostream>
#include "application.hpp"

int main()
{
    Application app;

    app.update();
    app.draw();
}
```

Looking nice isn't, it? All the real work is now hidden behind the `Application` class leaving our `main()` function all tidied up.

Application.hpp:

```cpp
#pragma once

#include <SDL2/SDL.h>
#include <iostream>

class Application
{
public:
    Application();
    ~Application();

    void update();
    void draw();
private:
    SDL_Window  *m_window;
    SDL_Surface *m_window_surface;
    SDL_Event    m_window_event;
};
```

Application.cpp:

```cpp
#include "application.hpp"

Application::Application()
{
    m_window = SDL_CreateWindow("SDL2 Window",
                                SDL_WINDOWPOS_CENTERED,
                                SDL_WINDOWPOS_CENTERED,
                                680, 480,
                                0);

    if(!m_window)
    {
        std::cout << "Failed to create window\n";
        std::cout << "SDL2 Error: " << SDL_GetError() << "\n";
        return;
    }

    m_window_surface = SDL_GetWindowSurface(m_window);

    if(!m_window_surface)
    {
        std::cout << "Failed to get window's surface\n";
        std::cout << "SDL2 Error: " << SDL_GetError() << "\n";
        return;
    }
}

Application::~Application()
{
    SDL_FreeSurface(m_window_surface);
    SDL_DestroyWindow(m_window);
}

void Application::update()
{
    bool keep_window_open = true;
    while(keep_window_open)
    {
        while(SDL_PollEvent(&m_window_event) > 0)
        {
            switch(m_window_event.type)
            {
                case SDL_QUIT:
                    keep_window_open = false;
                    break;
            }
        }

        draw();
    }
}

void Application::draw()
{
    SDL_UpdateWindowSurface(m_window);
}
```

Pretty much the same stuff from last time except now it's separated into two methods. `update()` checks if any events need to be processed and if there is none/if they all have been processed, call `draw()`.

What I want to bring to your attention is to the deconstructor of the class:

```cpp
Application::~Application()
{
    SDL_FreeSurface(m_window_surface);
    SDL_DestroyWindow(m_window);
}
```

This time we free the resources using `SDL_FreeSurface()` and `SDL_DestroyWindow()`.

Hopefully, this design will help with maintainability.

## SDL_Rect

Last time when we were blitting an image onto the window's surface we were using `SDL_BlitSurface()` and two of the four arguments that we can pass in were pointers to `SDL_Rect`s. We'll be utilizing `SDL_Rect` to position and scale our image.

First, we'll need an image to test on. I created a small stick figure in my favorite image manipulation program, GIMP. As you will soon see, I am no artist by any stretch of the imagination.

I've decided to create a helper function to load BMP images called `load_surface()`. I put it into the Application.cpp file but ideally, you should make a file for your helper functions unless they are closely related to the class, which in this case, they aren't.

```cpp
SDL_Surface *load_surface(char const *path)
{
    SDL_Surface *image_surface = SDL_LoadBMP(path);

    if(!image_surface)
        return 0;
    
    return image_surface;
}
```

Next, we will add two other member variables to our class called `m_image` and `m_image_position`.

```cpp
private:
    SDL_Surface *m_image;
    SDL_Rect     m_image_position;

    SDL_Window  *m_window;
    SDL_Surface *m_window_surface;
    SDL_Event    m_window_event;
```

If you were making a proper application, you would most likely (if you are using C++) wrap the `SDL_Surface` and `SDL_Rect` together and put the new class somewhere more sensible like a `Window` class for holding the contents of a window. We're just making a program to show a particular feature in SDL2 so this doesn't matter as much.

Next, we load the image and display it on the screen like last time. The image I'm using is 22 x 43.

In the constructor we add the following line of code:

```cpp
m_image = load_surface("stick_figure.bmp");
```

We'll skip the error checking for simplicity sake.

And in the `draw()` method I added the line of code to copy the pixels onto the screen.

```cpp
SDL_BlitSurface(m_image, NULL, m_window_surface, NULL);
```

Compile and run.

![](https://thepracticaldev.s3.amazonaws.com/i/6tseuhr96dhg0whv9s6y.png)

Our stick figure is in the top left corner of the window. Now let's animate him going to the right.

**Okay, so how do we accomplish that?**

Remember about `SDL_Rect`? That's what we're going to be using to move the image.

An `SDL_Rect` is made up of four members:

1. An x position
2. A y position
3. A width
4. A height

Before we blit the image, we can create an `SDL_Rect`, change some of its member fields and then pass it to the `SDL_BlitSurface()` function.*

*Okay, so I wasn't being entirely honest with you again. `SDL_BlitSurface()` is actually a macro that expands out to `SDL_UpperBlit()`. Why did they do this? I'm not sure.

In the `Application` class we added a member called `m_image_position`. This is going to be the `SDL_Rect` that controls how the image is positioned and scaled.

In the constructor, we add the code to set the member variables of `m_image_position` to the appropriate values.

```cpp
m_image_position.x = 0;
m_image_position.y = 0;
m_image_position.w = 22;
m_image_position.h = 43;
```

**Hold up! This is a bad design! Not all images are 22 x 43. There needs to be something more dynamic!**

Again, I'm trying to keep the code as simple as possible without sacrificing too many good practices. For now, just substitute the dimensions of your image.

```cpp
SDL_BlitSurface(m_image, NULL, m_window_surface, &m_image_position);
```

The last argument in `SDL_BlitSurface()` takes a pointer to an `SDL_Rect` and its the argument that decides what region of the window the image will be copied to and how it will be scaled.

Compile and run.

Some as last time.

**Can we please get to the animation?**

Yes, now that everything is in place, we can now animate the image.

In the `update()` method, we'll increment the image's x position by one every frame.

```cpp
m_image_position.x += 1;
```

Compile and run.

**Wow. That stick figure flew by.**

For some of you, you may not even see the stick figure. This is because your computer is running at maximum effort to move the image across the window.

**Okay, makes sense. How do we fix it?**

Easy, we need to scale the image's increment by how much time has passed since the last frame.

**So, how do we do that in SDL2?**

There is no `SDL_AmountOfTimeThatHasPassedSinceTheLastFrame()`* function. We'll have to come up with something.

*Can you imagine typing that lengthy function name?

But before we can do anything, we have to do some refactoring. Doesn't everyone love that?

We'll introduce a new method called `loop()` and now `update()` will take a `double`.

In main.cpp:

```cpp
Application app;

app.loop();
```

In Application.hpp:

```cpp
void loop();
void update(double delta_time);
```

With this new method in our class, we can move the event processing loop into it and now `update()` has only one job.

For now, I capped the frame rate to 60 frames per second by passing in `1.0/60.0` or approximately `0.01667` to `update()`. 

```cpp
void Application::loop()
{
    bool keep_window_open = true;
    while(keep_window_open)
    {
        while(SDL_PollEvent(&m_window_event) > 0)
        {
            switch(m_window_event.type)
            {
                case SDL_QUIT:
                    keep_window_open = false;
                    break;
            }
        }

        update(1.0/60.0);
        draw();
    }
}

void Application::update(double delta_time)
{
    m_image_position.x = m_image_position.x + (1 * delta_time);
}
```

We have another problem.

**What is it this time?**

If we manually calculate how much the stick figure will move per frame and place the result in `m_image_position.x` we get the value of zero. Why? It has to do something with how C++ work with different types with the same operator. C++ only uses the same types when using an operator so of one the operands will have to give. This is called the promotion rules*. For example, if one operand is a `double` then other will be converted to a `double`.

*At least that's what I call it.

So, `(1 * delta_time)` is converted to `(1.0 * delta_time)`.
After the subexpression is computed, the expression `m_image_position.x + result_of_subexpression` is calculated.

Because `m_image_position.x` is an `int` and `result_of_subexpression` is a `double` for reasons we saw earlier, the value in `m_image_position.x` will be promoted to a `double`.

Remember, I capped the frame rate to 60 fps by passing in `1.0/60.0` or approximately `0.01667` to `update()`. When we calculate the expression `m_image_position.x + (1 * 0.01667)` we get `0.01667`. I'll walk you though the steps. If `m_image_position.x` starts at 0:

`0 + (1 + 0.01667)`
`0 + (1.0 + 0.01667`
`0 + 0.01667`
`0.01667`

**Well, why isn't the stick figure moving about `0.01667` pixels per frame then?**

Simple: when you have a variable of type `int` and you try to put something in it with a type of `double` the fractional part gets truncated and only the whole number is placed into the value.

When we put `0.01667` into `m_image_position.x` it gets converted to an `int` because `m_image_position.x` is an `int`.

Effectively, we're moving zero pixels per second.

**Any ideas to fix this?**

Yup. We add two new variables of type `double` to our class.

```cpp
double       m_image_x;
double       m_image_y;
```

Ugh, we'll have to refactor this soon. This is getting out of hand.

In the constructor, we initialize both to `0.0`.

```cpp
m_image_x = 0.0;
m_image_y = 0.0;
```

```cpp
void Application::update(double delta_time)
{
    m_image_x = m_image_x + (5 * delta_time);
    m_image_position.x = m_image_x;
}
```

In this implementation, `m_image_x` keeps the fractional part of the calculation.

Compile and run.

![](https://thepracticaldev.s3.amazonaws.com/i/qvxwotv9h51hm2kmkant.png)

**Now there's some weirdness going on.**

It's because we're not clearing the screen before we draw leaving previously drawn items on the screen.

The simple fix is to add this line of code in `draw()` before the blitting:

```cpp
SDL_FillRect(m_window_surface, NULL, SDL_MapRGB(m_window_surface->format, 0, 0, 0));
```

I know it's a lot of new stuff that we haven't talked about, but let's step through this slowly.

SDL_FillRect fills a rectangular region on a surface with any color we want. We can choose to fill a region of the surface if we want. The last argument is the color that we want the filled region to be. It's a `Uint32` or simply an unsigned `int` that is 32 bits wide or 4 bytes. Fortunately, SDL2 provides a function called `SDL_MapRGB()` that takes four arguments.

1. The format of a surface.
2. The red value
3. The green value
4. The blue value

**I understand the last three arguments, but what is the first?**

In `SDL_Surface` there is a member variable which is a pointer to an `SDL_PixelFormat`. This contains information such as bit per pixel, masks for each component of a pixel, and has a member called `format`. It has the type of `SDL_PixelFormatEnum` and this is all the formats that SDL2 can work with. If you view the documentation, you will see a familiar acronym in some of the values like `SDL_PIXELFORMAT_RGB332` and some that you probably are not familiar with like `SDL_PIXELFORMAT_YVYU`. When we supply the format to `SDL_MapRGB()`, we are letting it know what version of the format we want to use.

Compile and run.

![](https://thepracticaldev.s3.amazonaws.com/i/ivweilu39ah96aw9wov1.png)

Now our stick figure moves across the screen without any weirdness.

## What's next?

In the next article, we'll gain control over the stick figure and move it however we like.

This part is probably the more information packed of the articles I've written so far. If you have any questions I'll be happy to answer them.

All code for this series can be found at my Github repository: https://github.com/Noah11012/sdl2-tutorial-code