Gigi Labs

Please follow Gigi Labs for the latest articles.
Showing posts with label c++. Show all posts
Showing posts with label c++. Show all posts

Sunday, March 30, 2014

SDL2: Animations with Sprite Sheets

Hi people! :)

[Update 2015-11-14: This article is out of date. Check out the latest version at Gigi Labs.]

We've worked with images in several of the SDL2 tutorials published so far. In today's article, we're going to use a very simple technique to animate our images and make them feel more alive.

Before we start, we first need to set up a new project as follows:

  1. Follow the steps in "SDL2: Setting up SDL2 in Visual Studio (2013 or any other)" to set up an SDL2 project.
  2. Follow the steps at the beginning of "SDL2: Loading Images with SDL_image" to use SDL_image in your project.
  3. Configure your project's working directory as described in "SDL2: Displaying text with SDL_ttf", i.e. in your project's Properties -> Configuration Properties -> Debugging, set Working Directory to $(SolutionDir)$(Configuration)\ .
  4. Start off with the following code, adapted from "SDL2: Loading Images with SDL_image":
#include <SDL.h>
#include <SDL_image.h>

int main(int argc, char ** argv)
{
    bool quit = false;
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_PNG);

    SDL_Window * window = SDL_CreateWindow("SDL2 Sprite Sheets",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
        480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Surface * image = IMG_Load("spritesheet.png");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);

    while (!quit)
    {
        SDL_WaitEvent(&event);

        switch (event.type)
        {
        case SDL_QUIT:
            quit = true;
            break;
        }

        SDL_RenderCopy(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);
    }

    SDL_DestroyTexture(texture);
    SDL_FreeSurface(image);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();

    return 0;
}


Before we do anything, we need a sprite sheet. A sprite sheet is really just a cartoon. Like this:


This image is 128 pixels wide and 64 pixels high. It consists of 4 sub-images (called sprites or frames), each 32 pixels wide. If we can rapidly render each image in quick succession, just like a cartoon, then we have an animation! :D

Now, those ugly borders in the image above are just for demonstration purposes. Here's the same image, without borders and with transparency:


If we now try to draw the above on the default black background, we're not going to see anything, are we? Fortunately, it's easy to change the background colour, and we've done it before in "SDL2: Keyboard and Mouse Movement (Events)". Just add the following two lines before the while loop:

    SDL_SetRenderDrawColor(renderer, 168, 230, 255, 255);
    SDL_RenderClear(renderer);


Now we get an early peek at what the output is going to look like. Press Ctrl+Shift+B to build the project, and then copy SDL2.dll, all the SDL_image DLLs, and the spritesheet into the Debug folder where the executable is generated.

Once that is done, hit F5:


So at this point, there are two issues we want to address. First, we don't want our image to take up the whole window, as it's doing above. Secondly, we only want to draw one sprite at a time. Both of these are pretty easy to solve if you remember SDL_RenderCopy()'s last two parameters: a source rectangle (to draw only a portion of the image) and a destination rectangle (to draw the image only to a portion of the screen).

So let's add the following at the beginning of the while loop:

        SDL_Rect srcrect = { 0, 0, 32, 64 };
        SDL_Rect dstrect = { 10, 10, 32, 64 };


...and then update our SDL_RenderCopy() call as follows:

        SDL_RenderCopy(renderer, texture, &srcrect, &dstrect);


Note that the syntax we're using to initialise our SDL_Rects is just shorthand to set all of the x, y, w (width) and h (height) members all at once.

Let's run the program again and see what it looks like:


Okay, so like this we are just rendering the first sprite to a part of the window. Now, let's work on actually animating this. At the beginning of the while loop, add the following:

        Uint32 ticks = SDL_GetTicks();


SDL_GetTicks() gives us the number of milliseconds that passed since the program started. Thanks to this, we can use the current time when calculating which sprite to use. We can then simply divide by 1000 to convert milliseconds to seconds:

        Uint32 seconds = ticks / 1000;


We then divide the seconds by the number of sprites in our spritesheet, in this case 4. Using the modulus operator ensures that the sprite number wraps around, so it is never greater than 3 (remember that counting is always zero-based, so our sprites are numbered 0 to 3).

        Uint32 sprite = seconds % 4;


Finally, we replace our srcrect declaration by the following:

        SDL_Rect srcrect = { sprite * 32, 0, 32, 64 };


Instead of using an x value of zero, as we did before, we're passing in the sprite value (between 0 and 3, based on the current time) multiplied by 32 (the width of a single sprite). So with each second that passes, the sprite will be extracted from the image at x=0, then x=32, then x=64, then x=96, back to x=0, and so on.

Let's run this again:


You'll notice two problems at this stage. First, the animation is very irregular, in fact it doesn't animate at all unless you move the mouse or something. Second, the sprites seem to be dumped onto one another, as shown by the messy image above.

Fortunately, both of these problems can be solved with code we've already used in "SDL2: Keyboard and Mouse Movement (Events)". The first issue is because we're using SDL_WaitEvent(), so the program doesn't do anything unless some event occurs. Thus, we need to replace our call to SDL_WaitEvent() with a call to SDL_PollEvent():

        SDL_PollEvent(&event);


The second problem is because we are drawing sprites without clearing the ones we drew before. All we need to do is add a call to SDL_RenderClear() before we call SDL_RenderCopy():

        SDL_RenderClear(renderer);


Great! You can now admire our little character shuffling at one frame per second:


It's good, but it's a bit slow. We can make it faster by replacing the animation code before the srcrect declaration with the following (10 frames per second):

        Uint32 ticks = SDL_GetTicks();
        Uint32 sprite = (ticks / 100) % 4;


Woohoo! :D Look at that little guy dance!

So in this article, we learned how to animate simple characters using sprite sheets, which are really just a digital version of a cartoon. We used SDL_RenderCopy()'s srcrect parameter to draw just a single sprite from the sheet at a time, and selected that sprite using the current time based on SDL_GetTicks(). The full code is below.

Thanks for reading! Stay tuned for more articles. :)

#include <SDL.h>
#include <SDL_image.h>

int main(int argc, char ** argv)
{
    bool quit = false;
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_PNG);

    SDL_Window * window = SDL_CreateWindow("SDL2 Sprite Sheets",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
        480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Surface * image = IMG_Load("spritesheet.png");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);

    SDL_SetRenderDrawColor(renderer, 168, 230, 255, 255);
    SDL_RenderClear(renderer);

    while (!quit)
    {
        Uint32 ticks = SDL_GetTicks();
        Uint32 sprite = (ticks / 100) % 4;
        SDL_Rect srcrect = { sprite * 32, 0, 32, 64 };
        SDL_Rect dstrect = { 10, 10, 32, 64 };

        SDL_PollEvent(&event);

        switch (event.type)
        {
        case SDL_QUIT:
            quit = true;
            break;
        }

        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, &srcrect, &dstrect);
        SDL_RenderPresent(renderer);
    }

    SDL_DestroyTexture(texture);
    SDL_FreeSurface(image);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();

    return 0;
}

Saturday, March 29, 2014

SDL2: Displaying text with SDL_ttf

Hello again! :)

[Update 2015-11-14: This article is out of date. Check out the latest version at Gigi Labs.]

In this article, we're going to learn how we can write text in our window. To do this, we'll use the SDL_ttf library.

First, we need to set up a project to work with SDL2. To do this, follow the instructions in my earlier article, "SDL2: Setting up SDL2 in Visual Studio (2013 or any other)".

Next, we need to actually download and use the SDL_ttf library. This is very similar to what we did with SDL_image in "SDL2: Loading Images with SDL_image". First, download the Visual C++ Development Libraries from the SDL_ttf 2.0 homepage:


From the archive you just downloaded, you need to do the same as in "SDL2: Loading Images with SDL_image" to:

  1. Copy SDL_ttf.h to the include folder where your other SDL2 files reside.
  2. Copy SDL2_ttf.lib to the lib\x86 folder where your other SDL2 files reside.
  3. After compiling your project (as it is, without using SDL_ttf just yet), copy the DLL files from the lib\x86 folder, as well as the regular SDL2.dll, to the Debug folder where your project's executable is created.

Then, in your project's properties, go to Linker -> Input and add the following: SDL2_ttf.lib in the Additional Dependencies field. This field should now contain the following:

SDL2.lib; SDL2main.lib; SDL2_ttf.lib

Good. Now, let's start with the following code which is a modified version of the code from about halfway through "SDL2: Displaying an Image in the Window":

#include <SDL.h>

int main(int argc, char ** argv)
{
 bool quit = false;
 SDL_Event event;

 SDL_Init(SDL_INIT_VIDEO);

 SDL_Window * window = SDL_CreateWindow("SDL_ttf in SDL2",
  SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
  480, 0);
 SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

 while (!quit)
 {
  SDL_WaitEvent(&event);

  switch (event.type)
  {
  case SDL_QUIT:
   quit = true;
   break;
  }
 }

 SDL_DestroyRenderer(renderer);
 SDL_DestroyWindow(window);
 SDL_Quit();

 return 0;
}

The first thing we need to do in order to use SDL_ttf is include the relevant header file:

#include <SDL_ttf.h>

Then, we initialise the SDL_ttf library right after we call SDL_Init():

 TTF_Init();

...and we clean it up just before we call SDL_Quit():

 TTF_Quit();

Right after we initialise our renderer, we can now load a font into memory:

 TTF_Font * font = TTF_OpenFont("arial.ttf", 25);

TTF_OpenFont() takes two parameters. The first is the path to the TrueType Font (TTF) that it needs to load. The second is the font size (in points, not pixels). In this case we're loading Arial with a size of 25.

A font is a resource like any other, so we need to free the resources it uses near the end:

 TTF_CloseFont(font);

We can now render some text to an SDL_Surface using TTF_RenderText_Solid(). which takes the font we just created, a string to render, and an SDL_Color which we are passing in as white in this case:

 SDL_Color color = { 255, 255, 255 };
 SDL_Surface * surface = TTF_RenderText_Solid(font,
  "Welcome to Programmer's Ranch", color);

We can then create a texture from this surface as we did in "SDL2: Displaying an Image in the Window":

 SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
  surface);

And yet again, we should not forget to release the resources we just allocated near the end, so let's do that right away:

 SDL_DestroyTexture(texture);
 SDL_FreeSurface(surface);

Now all we need is to actually render the texture. We've done this before; just add the following just before the end of your while loop:

  SDL_RenderCopy(renderer, texture, NULL, NULL);
  SDL_RenderPresent(renderer);

Okay, now before we actually run this program, we need to put our Arial TTF font somewhere where our program can find it. Go to C:\Windows\Fonts, and fron there copy the Arial font into the Debug folder where your executable is compiled. This will result in several TTF files, although we're only going to use arial.ttf.

Now if you've read my SDL_image tutorials before, you'll know that the program runs from a different directory when running from Visual Studio and when running directly from the executable - in fact if you run the program now from Visual Studio, it will crash; but if you run the executable directly it will work fine. Rather than replicating our TTF file across folders to satisfy both scenarios, here's a little trick to make it work without further ado.

Go into your project properties, and then under Configuration Properties -> Debugging, there's a field called Working Directory. Change this from $(ProjectDir) (the default setting) to $(SolutionDir)$(Configuration)\ :


Great, now let's admire the fruit of our work:


Nooooooooooooooo! This isn't quite what we were expecting, right? This is happening because the texture is being stretched to fill the contents of the window. The solution is to supply the dimensions occupied by the text in the dstrect parameter of SDL_RenderCopy() (as we did in "SDL2: Displaying an Image in the Window"). But how can we know these dimensions?

If you check out Will Usher's SDL_ttf tutorial, you'll realise that a function called SDL_QueryTexture() can give you exactly this information (and more). So before our while loop, let's add the following code:

 int texW = 0;
 int texH = 0;
 SDL_QueryTexture(texture, NULL, NULL, &texW, &texH);
 SDL_Rect dstrect = { 0, 0, texW, texH };

Finally, we can pass dstrect in our call to SDL_RenderCopy():

  SDL_RenderCopy(renderer, texture, NULL, &dstrect);

Let's run the program now:


Much better! :)

In this article, we learned how to use the SDL_ttf to render text using TTF fonts in SDL2. Using the SDL_ttf library in a project was just the same as with SDL_image. To actually use fonts, we first rendered text to a surface, then passed it to a texture, and finally to the GPU. We used SDL_QueryTexture() to obtain the dimensions of the texture, so that we could render the text in exactly as much space as it needed. We also learned how we can set up our project to use the same path regardless of whether we're running from Visual Studio or directly from the executable.

Below is the full code for this article. Come back again for more! :)

#include <SDL.h>
#include <SDL_ttf.h>

int main(int argc, char ** argv)
{
 bool quit = false;
 SDL_Event event;

 SDL_Init(SDL_INIT_VIDEO);
 TTF_Init();

 SDL_Window * window = SDL_CreateWindow("SDL_ttf in SDL2",
  SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
  480, 0);
 SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

 TTF_Font * font = TTF_OpenFont("arial.ttf", 25);
 const char * error = TTF_GetError();
 SDL_Color color = { 255, 255, 255 };
 SDL_Surface * surface = TTF_RenderText_Solid(font,
  "Welcome to Programmer's Ranch", color);
 SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
  surface);

 int texW = 0;
 int texH = 0;
 SDL_QueryTexture(texture, NULL, NULL, &texW, &texH);
 SDL_Rect dstrect = { 0, 0, texW, texH };

 while (!quit)
 {
  SDL_WaitEvent(&event);

  switch (event.type)
  {
  case SDL_QUIT:
   quit = true;
   break;
  }

  SDL_RenderCopy(renderer, texture, NULL, &dstrect);
  SDL_RenderPresent(renderer);
 }

 SDL_DestroyTexture(texture);
 SDL_FreeSurface(surface);
 TTF_CloseFont(font);

 SDL_DestroyRenderer(renderer);
 SDL_DestroyWindow(window);
 TTF_Quit();
 SDL_Quit();

 return 0;
}

Sunday, March 16, 2014

C: Rock, Scissors, Paper (using random numbers)

Hello everyone, and welcome back to the Ranch! :)

In my last C article, "C: Calculating the Average of Several Numbers", we learned how to work with numbers in C. This included using integer variables, input/output of integers, and arithmetic operations.

Today, we're going to take this further and learn how to generate random numbers in C. We'll use this to write a little Rock, Scissors, Paper game.

Pseudo-random numbers in C


So let's start off with a pretty empty program:

#include <stdio.h>

int main(int argc, char ** argv)
{
    return 0;
}

We can generate a random integer using the rand() function, which is defined in stdlib.h. This gives us a random number between 0 and a constant integer called RAND_MAX. We can output the value of RAND_MAX as we would any other integer, although its value is not guaranteed to be the same across different computers:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char ** argv)
{
    int a = rand();
    int b = rand();
    int c = rand();

    printf("RAND_MAX is: %d\n", RAND_MAX);
    printf("a is: %d\n", a);
    printf("b is: %d\n", b);
    printf("c is: %d\n", c);

    return 0;
}

Let us now run this program a few times and see what happens:


On my computer, RAND_MAX is defined as 2147483647, so each time I call rand(), it will give me a random number between 0 and 2147483647.

Another thing you'll see from the output is that each time I run the program, I get the same values for a, b and c. That isn't quite random, is it?

The reason why this is happening is that these random numbers aren't really random.  They are actually generated from a mathematical sequence, that takes a very, very long time to begin repeating itself, but which isn't truly random. These are called pseudo-random numbers. Imagine this sequence:

4, 29, 55, 12, 4, 7, 3, 97, 84, ...

This sequence seems pretty random; there isn't any pattern in it. So each time we get a random number with rand(), we'll get a different number: first 4, then 29, then 55, etc.

Our problem is that each time we run the program, we're starting from the beginning of the sequence, and this gives us the same values. So what we want to do is start from a different position each time.

We do this by seeding the pseudo-random number generator using the srand() function. Let's just add this line at the beginning of main():

    srand(100);

Let's run the program again:


You'll notice the numbers have changed, since we're using a different seed. However, each time we run the program, the same numbers are repeated. In fact we are still making the same mistake as before: we are using the same seed, and starting the pseudo-random number sequence from the same point each time.

In order to use a different seed each time we run the program, we can use the current time as the seed. We can use the time() function, defined in time.h, to give us the current time. So let's include that header file at the top...

#include <time.h>

...and replace our call to srand() with this:

srand(time(NULL));

When we run the program, things work as we expect, and we get different pseudorandom numbers each time we run:


Scaling random numbers


Great. Now, the numbers we are generating are a little bit big. For example, for Rock, Scissors, Paper, we don't need a number between 0 and 2147483647; all we need is a number between 1 and 3 (both inclusive), to represent either rock, scissors, or paper. We can limit the range of a pseudorandom number by dividing it by the maximum we want, and extracting the remainder. This is done using the modulus (%) operator, which gives us the remainder of a division:

    int a = rand() % 10;
    int b = rand() % 10;
    int c = rand() % 10;

Let's say rand() gives us 55. If we divide 55 by 10, then the remainder can be at most 9. So what we're doing above is limiting each random number to the range 0 to 9 (both inclusive). We'll need to add 1 to the number by which we're dividing, in order to make it inclusive (i.e. between 0 and 10 in this case).

What if we need a minimum value that is not zero? In short, we declare a general-purpose function that returns random integers between two integers (both inclusive) like this:

// returns a random number between min and max, both inclusive)
int randomInt(int min, int max)
{
    return min + (rand() % (max - min + 1));
}

We can then use this function from within our main() like this, to give us random numbers between 1 and 10:

    int a = randomInt(1, 10);
    int b = randomInt(1, 10);
    int c = randomInt(1, 10);

And voilà:


Rock, Scissors, Paper in C


OK, so now that we know how to generate pseudorandom numbers, we can write out game of Rock, Scissors, Paper. In this game, two people independently choose one of rock, scissors or paper, and state their choice at the same time. The outcome is then as follows:

  • Rock beats scissors (breaks it).
  • Scissors beats paper (cuts it).
  • Paper beats rock (wraps it).

To start off, let's throw away all our code in main(), but keep our randomInt() function:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// returns a random number between min and max, both inclusive)
int randomInt(int min, int max)
{
    return min + (rand() % (max - min + 1));
}

int main(int argc, char ** argv)
{
    // code goes here

    return 0;
}

First, we add code to accept user input:

    int input = -1;

    while (input != 0)
    {
        printf("Choose...\n");
        printf("   1 for rock\n");
        printf("   2 for scissors\n");
        printf("   3 for paper\n");
        printf("or 0 to exit\n");

        scanf("%d", &input);
    }

The user will choose a number between 1 and 3 to represent rock, scissors, or paper respectively. A while loop repeats the game until the user enters 0 to exit the game. We have already used for loops in C: Calculating the Average of Several Numbers, but a while loop will simply keep executing the code within curly brackets as long as the condition within round brackets is true, in this case as long as input is not zero:


Once the human player has chosen, the computer player makes his choice at random:

       int computerChoice = randomInt(1, 3);

We can then display the computer's choice:

       switch(computerChoice)
       {
           case 1: printf("Computer chooses rock\n"); break;
           case 2: printf("Computer chooses scissors\n"); break;
           case 3: printf("Computer chooses paper\n"); break;
       }

A switch statement allows us to specify separate code to be executed depending on the value of a variable. In this case, if computerChoice is 1, we write that the computer has chosen rock, and similarly for the other choices. Note that each case in a switch statement should always end in a break statement; otherwise unexpected things may happen. :)

Finally, we can add the game logic to check who won:

       if (input == computerChoice)
       {
           printf("Game ends in a draw.\n");
       }
       else if (input == 1 && computerChoice == 2)
       {
          printf("Rock beats scissors! You win!\n");
       }
       else if (input == 2 && computerChoice == 3)
       {
          printf("Scissors beats paper! You win!\n");
       }
       else if (input == 3 && computerChoice == 1)
       {
          printf("Paper beats rock! You win!\n");
       }
       else if (computerChoice == 1 && input == 2)
       {
          printf("Rock beats scissors! Computer wins!\n");
       }
       else if (computerChoice == 2 && input == 3)
       {
          printf("Scissors beats paper! Computer wins!\n");
       }
       else if (computerChoice == 3 && input == 1)
       {
          printf("Paper beats rock! Computer wins!\n");
       }

Using a cascade of if statements, we compare the user input with the computer's random choice and see who won. The == operator allows us to compare two integers and determine whether they are equal. The && operator, on the other hand, is a boolean AND operator. If both conditions around the && operator are true, then the printf() statement within the curly brackets of that if statement is executed.

We can now actually play our game:


Summary


Great! :) We have a fully working Rock, Scissors, Paper game here. And in creating it, we learned about pseudo-random numbers, while loops, if statements, switch statements, and also a few operators including == (is equal to), != (is not equal to) and && (boolean AND). Below is the full code.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// returns a random number between min and max, both inclusive)
int randomInt(int min, int max)
{
    return min + (rand() % (max - min + 1));
}

int main(int argc, char ** argv)
{
    int input = -1;

    while (input != 0)
    {
        printf("Choose...\n");
        printf("   1 for rock\n");
        printf("   2 for scissors\n");
        printf("   3 for paper\n");
        printf("or 0 to exit\n");

        scanf("%d", &input);

       int computerChoice = randomInt(1, 3);

       switch(computerChoice)
       {
           case 1: printf("Computer chooses rock\n"); break;
           case 2: printf("Computer chooses scissors\n"); break;
           case 3: printf("Computer chooses paper\n"); break;
       }

       if (input == computerChoice)
       {
           printf("Game ends in a draw.\n");
       }
       else if (input == 1 && computerChoice == 2)
       {
          printf("Rock beats scissors! You win!\n");
       }
       else if (input == 2 && computerChoice == 3)
       {
          printf("Scissors beats paper! You win!\n");
       }
       else if (input == 3 && computerChoice == 1)
       {
          printf("Paper beats rock! You win!\n");
       }
       else if (computerChoice == 1 && input == 2)
       {
          printf("Rock beats scissors! Computer wins!\n");
       }
       else if (computerChoice == 2 && input == 3)
       {
          printf("Scissors beats paper! Computer wins!\n");
       }
       else if (computerChoice == 3 && input == 1)
       {
          printf("Paper beats rock! Computer wins!\n");
       }
    }

    return 0;
}

Monday, November 25, 2013

SDL2: Loading Images with SDL_image

Welcome!

[Update 2015-11-14: This article is out of date. Check out the latestversion at Gigi Labs.]

In the previous article, "SDL2: Displaying an Image in the Window", we saw how we could load bitmaps using the SDL_LoadBMP() function. Unfortunately, working with bitmaps is very limiting, and the core SDL2 library does not provide the means to work with other image formats. However, such functionality is provided by an extension library called SDL_image. In this article, we will learn how to set up SDL_image and also how to use it to load other image formats.

Setting up SDL_image is not very different from setting up SDL 2.0 itself. You need to go to the SDL_image homepage and download the development libraries and runtime binaries:


Let's concentrate on those development libraries for the moment. Once you extract the contents of the zip file, you'll be able to find an include folder and a lib folder among other stuff. The include folder contains a single header file, SDL_image.h. This needs to go into your C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include\SDL2 folder (this is for Visual Studio 2010; you may need to change the v7.0A part depending on the version you're using), or wherever your other SDL2 header files are located, and drop the SDL_image.h file there.

As for the lib folder, whatever is in the x86 subfolder goes into the C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib folder, and whatever is in the x64 subfolder goes into C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib\x64.

With that done, let's set up a new project using Visual Studio 2010. Create an Empty Project from the Visual C++ category. Right click on the project and select Properties. In Configuration Properties -> Linker -> System, change the SubSystem to Windows (/SUBSYSTEM:WINDOWS). Then go to Input (also under Linker) and replace the Additional Dependencies with the following:

SDL2.lib;SDL2main.lib;SDL2_image.lib

You'll notice this is a little different from "SDL2: Setting up SDL2 in Visual Studio 2010" in that we've added the SDL2_image.lib. Since this is a new library, we need to link it into our program to use its functionality.

Now let's try some code. Add a file called main.cpp, and let's start off with the following code (it's the same as that used in "SDL2: Displaying an Image in the Window", without the error checking to keep it concise, and also filling the window):
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

int main(int argc, char ** argv)
{
    bool quit = false;
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);

    SDL_Window * window = SDL_CreateWindow("SDL2 Displaying Image",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Surface * image = SDL_LoadBMP("image.bmp");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);

    while (!quit)
    {
       SDL_WaitEvent(&event);

       switch(event.type)
       {
       case SDL_QUIT:
           quit = true;
           break;
       }

       SDL_RenderCopy(renderer, texture, NULL, NULL);
       SDL_RenderPresent(renderer);
    }

    SDL_DestroyTexture(texture);
    SDL_FreeSurface(image);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

Now, we're going to load this nice photo (.jpg format) taken in Gardaland in 2006:


Doing this is quite simple. First, we initialise SDL_image by calling IMG_Init() right after the call to SDL_Init():
    IMG_Init(IMG_INIT_JPG);
...and before the call to SDL_Quit(), we shut down SDL_Image using IMG_Quit():

    IMG_Quit();
All we have left to do now is replace the line calling SDL_LoadBMP() with one that uses IMG_Load() instead:
    SDL_Surface * image = IMG_Load("PICT3159.JPG");
You should now be able to build this program (Ctrl+Shift+B). Before you run it, though, make sure that SDL2.dll is in the same folder as your executable. You'll also need to toss in all the DLLs from the runtime binaries package (most likely the x86 one is what you'll be using by default) - that includes SDL2_image.dll along with format-specific files such as libjpeg-9.dll, libpng16-16.dll, etc. If you're going to run from Visual Studio, make sure the image is in the same folder as your main.cpp file; otherwise if you're running straight from the executable, the image should be in the same folder with it.

And voilà:


Isn't that sweet? The SDL_image library allows you to load a large variety of image formats, by just replacing SDL_LoadBMP() with IMG_Load(). You'll need to initialise and cleanup the library (although it seems to work even without this) and remember to link the library and include the appropriate header file. But as you can see, it's pretty straightforward.

Sunday, November 17, 2013

SDL2: Displaying an Image in the Window

Hello! :)

[Update 2015-11-14: This article is out of date. Check out the latestversion at Gigi Labs.]

In this article we're going to learn how to load a bitmap image from disk and display it in an SDL2 window. In order to follow along, you'll need to set up a project to work with SDL (see "SDL2: Setting up SDL2 in Visual Studio 2010"), and start off with the basic empty window code from SDL2: Empty Window, which is this:

    #include <SDL2/SDL.h>        
            
    int main(int argc, char ** argv)        
    {        
        bool quit = false;        
        SDL_Event event;        
            
        SDL_Init(SDL_INIT_VIDEO);        
            
        SDL_Window * screen = SDL_CreateWindow("My SDL Empty Window",
            SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480,
            0);        
            
        while (!quit)        
        {        
           SDL_WaitEvent(&event);        
            
           switch(event.type)        
           {        
           case SDL_QUIT:        
               quit = true;        
               break;        
           }        
        }        
            
        SDL_Quit();        
            
        return 0;        
    }

Build the application. Remember to place SDL2.dll into your bin\Debug folder. The empty window should appear if you run the application, and you should be able to close it by clicking on the "X" at the top-right corner.

Let's first change the window declaration a little bit (I changed the name of the variable and the window title):

    SDL_Window * window = SDL_CreateWindow("SDL2 Displaying Image",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);

After that, let's create an SDL_Renderer:

    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);

We use SDL_CreateRenderer() to get an instance of SDL_Renderer. This renderer represents the output device (usually your graphics card) to which your code will be drawing. In fact it's the final destination of our image, because we'll be following the steps below:


SDL_CreateRenderer() takes three parameters. The first is the window where we are drawing. The second allows us to select different rendering drivers; in our case we don't care, and we can set it to -1 and get the default one. The last parameter allows us to set SDL_RendererFlags to control how the rendering occurs. We can set it to zero to default to hardware rendering. If any of this sounds confusing, don't worry about it and just use SDL_CreateRender() as it is here.

We can now load the image from disk using the SDL_LoadBMP() function, which takes a path to a bitmap and loads it into an SDL_Surface:

    SDL_Surface * image = SDL_LoadBMP("image.bmp");

I'm using the following photo of the Grand Harbour in Valletta, Malta, which I took back in 2005, and which has a width of 320 pixels and a height of 240 pixels:


Place the image in your bin\Debug folder, where your executable is located.

Next, we need to create a texture.

    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);

A texture is memory close to the graphics card (see image below), and we use SDL_CreateTextureFromSurface() to directly map our surface (which contains the image we loaded) to a texture.


Now that we have a texture, let's display it in the window. At the end of the while loop, just after the switch statement, add the following:

        SDL_RenderCopy(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);

We use SDL_RenderCopy() to copy the texture to the output device. There are also a couple of other parameters that we're setting to NULL - more on these in a minute. Finally, SDL_RenderPresent() is what commits the texture to the video memory, displaying the image.

Before we run the program, we must always remember to clean up every resource that we initialise. In our case, that means adding the following just before the call to SDL_Quit():

    SDL_DestroyTexture(texture);  
    SDL_FreeSurface(image);  
    SDL_DestroyRenderer(renderer);  
    SDL_DestroyWindow(window);

If you now run the program from within Visual Studio, surprisingly enough, you get a blank window:


...whereas if you run the program directly from the executable in your solution's bin\Debug folder (where image.bmp is also located), it works:


We'd know more about what's going on if we had proper error handling in place. With every call to the SDL2 API, we should be checking the return values, and displaying an error if any of them fail. SDL_ShowSimpleMessageBox() is great for displaying simple error messages, while SDL_GetError() gives us the actual error text of the last thing that failed. Let's refactor our initialisation code to check for errors and display them:

    SDL_Window * window = SDL_CreateWindow("SDL2 Displaying Image",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
    if (window == NULL)
        SDL_ShowSimpleMessageBox(0, "Window init error", SDL_GetError(),
            window);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    if (renderer == NULL)
        SDL_ShowSimpleMessageBox(0, "Renderer init error",
            SDL_GetError(), window);
    SDL_Surface * image = SDL_LoadBMP("image.bmp");
    if (image == NULL)
        SDL_ShowSimpleMessageBox(0, "Image init error", SDL_GetError(),
            window);
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);
    if (texture == NULL)
        SDL_ShowSimpleMessageBox(0, "Texture init error",
            SDL_GetError(), window);

When we run this code, the first error we get is the following:


That's it - the program can't find the image. Remember how it worked when running from the executable, but not from Visual Studio? That's because Visual Studio starts at a different directory. As a quick workaround, just copy image.bmp into your source folder (where main.cpp is located). Hit F5, and it now works:


Fantastic! The image is right there in the window! But... can you see what happened? The image, which has dimensions 320x240, has been stretched to fill the window, which has dimensions 640x480. That's sometimes convenient, because we get scaling for free. However, it makes photos look messy. Let's change our call to SDL_RenderCopy() to fix this:

        SDL_Rect dstrect = { 5, 5, 320, 240 };
        SDL_RenderCopy(renderer, texture, NULL, &dstrect);

Remember those two parameters at the end of SDL_RenderCopy() that we were setting to NULL? If you look at the documentation for SDL_RenderCopy(), you'll see that the last one defines a destination region (which part of the texture will the image be copied to). If it's set to NULL, then the image is stretched to fill the texture - which is what happened above.

By setting dstrect (the last parameter), we can render to only a portion of the window. We set it to an SDL_Rect, with x and y set to 5, and width and height corresponding to the dimensions of the image. When we run the program, we get this:


Excellent! :) In this article we looked at how to create renderers, surfaces and textures. We used these to load bitmaps and display them on the screen. A glimpse into error handling allowed us to troubleshoot issues with loading the image from Visual Studio. Finally, we saw the difference between copying the image to a region of the window, and making it fill the entire window.

I hope you enjoyed this. Come back for more! :)

Saturday, November 9, 2013

C: Calculating the Average of Several Numbers

Hello everyone! :)

In my article "C: Hello World on Linux", we saw how to write a very simple C program, and how to compile and run it on Linux. In this article, we'll learn how to work with numbers in C, and also how to accept input and print output. I like to use Linux when writing or teaching C/C++, but you can just as well follow along if you're on Windows (e.g. by using Microsoft Visual C++). If you're going to use Linux, you can use your distribution's text editor, or else something like vi (check out my articles, "Linux: vi Essentials" and "Linux: Navigating Text with vi", if you feel you need a refresher on vi).

So, we'll begin with the following basic template:

#include <stdio.h>

int main(int argc, char ** argv)
{
    return 0;
}

Including the stdio.h header file gives us access to the input/output (I/O) functions that we'll need. The first of these is printf(), which we've already seen in my original article, "C: Hello World on Linux".

In our program, we're first going to ask the user how many numbers he's going to enter. Let's say he enters 5. In that case, we'll ask him for five numbers, and then add them up, and then compute the average.

Before the return statement, add the following:

    printf("How many numbers do you want to average?\n");

The \n translates to a newline.

We then declare a variable called count, of type int (integer), so that we can store how many numbers the user needs to enter:

    int count = 0;

Just a note... in C/C++ it is important to always initialise your variables with a value. If you don't, they will contain random garbage data, and using them before they're assigned might lead to unpredictable results.

Now, we can then use the scanf() function to accept input, as follows:

    scanf("%d", &count);

This looks pretty scary, doesn't it? The first parameter is a format string; it indicates what kind of data you're trying to accept. In this case, %d means we are expecting an integer. The second parameter indicates the variable where we'll store the input. By preceding the count variable with the & symbol, we're telling scanf() that the input should go to the location in memory where count resides. This might sound a bit weird until we talk about pointers and references (because it is), but just remember to include that & when accepting input, and you'll be fine.

Next, we need a few new variables:

    int i = 0;
    int number = 0;
    int total = 0;

We'll accept each number into the number variable, after which we'll add it to total. The i variable will be used to track how many numbers have been accepted, so that we know when to stop.

Next, we can write a for loop to repeatedly accept numbers as input, until we have reached the number of numbers we were expecting:

    for (i = 0; i < count; i++)
    {

    }

The code inside the curly brackets (which we will write shortly) will execute as many times as the count variable is set to. If count is 5, then it will execute 5 times. If you look at the first line of the for loop, we're starting with i set to zero, and we're telling it to continue executing as long as i is less than count. Each time the loop's code executes, i is increased by 1 (that's the i++ bit), until the i < count condition becomes true and the loop ends.

Sidenote: if you're coming from some other language, you might be wondering why I didn't declare i in the for loop. That's because some versions of C don't allow it (although it's fine in C++), so you may end up with an error like this:

error: ‘for’ loop initial declarations are only allowed in C99 mode

Let's add some code inside the for loop to accept numbers as input:

        printf("Enter number %d of %d: ", i, count);
        scanf("%d", &number);
        total = total + number;

In the first line, we can see the use of the %d (integer) placeholder within printf(). When you run the program, the placeholders are replaced with the other parameters, i.e. the first %d is replaced with the value of i, and the second one is replaced with the value of count.

In the second line, we're accepting a number as input, and storing it in the number variable (remember the &). Finally, in the third line, we add number to total. There's actually a more concise and efficient way of adding a value to a variable, which is the following:

        total += number;

After the end of the for loop, we can now calculate the average by dividing total by the number of items (count):

    float average = total / count;
    printf("Average: %f\n", average);

The float data type allows us to store numbers that are not integers (whole numbers), and which might have some decimal value. When using floats with printf(), we need to use the %f placeholder, instead of the %d that is used for integers.

Here's the code we have so far, with syntax highlighting courtesy of vim:


From the Linux terminal, the following command will compile your code to an executable called average:

gcc average.c -o average

...and the following command executes it:

./average

Let's test the program to see that it works correctly:


Hmmm, wait just a minute. 1 + 2 + 4 gives us 7, and divided by 3, that doesn't give us exactly 2 (it's actually 2.333333.....). The problem is in the following line of code:

    float average = total / count;

We're dividing an integer by another integer, and that gives us back an integer - losing any digits after the decimal point. To get this to work correctly, we can convert count to a float as follows:

    float average = total / (float) count;

This is called type casting: you put a data type in brackets before a variable to indicate that it should be interpreted as the specified data type. When we recompile and run the program, we can see that it now behaves as we originally expected:


Nice! :)

This article showed how to write a simple program - one that calculates the average of a set of numbers - in C. This simple program revealed several features of the C language, including input/output (via printf() and scanf()), placeholders for format strings (%d and %f), int and float variables, for loops, and type casting.

I hope you found this interesting. Stick around for more articles! :)

Wednesday, August 7, 2013

C: Hello World on Linux

Hello people!

Today I'm going to describe how you go about writing, compiling and executing C code using the Linux command line (also known as shell or terminal).

You will first need to make sure you have the tools necessary to compile C code. In particular you need gcc. You can get it by installing the build-essential package. On a Debian-based Linux distribution such as Ubuntu, you'd use the following command in the terminal:

sudo apt-get install build-essential

...and then, after entering the root password (if necessary), you proceed with the installation:


To actually write the C code, you can use the vi editor. Even better, you can make sure that you have the vim (vi improved) by using the following command:

sudo apt-get install vim

Then use the following command to edit a file called hello.c (it doesn't need to exist yet):

vi hello.c

This opens the vi editor. vi is very powerful but takes a little getting used to. You start off in command mode, and just about any letter you type has a particular meaning. If you press the 'I' key, you go into insert mode, and can type code to your heart's content. Do that, and enter the following code:

#include <stdio.h>

int main(int argc, char ** argv)
{
    printf("Hello world!\n");

    return 0;
}

Over here we're first including the stdio.h library, which allows us to do input/output (I/O) such as outputting text to the terminal. The actual code goes into the main() function, which returns an integer. You can ignore the argc and argv bits, and just use this as a template for your code, for the time being. We actually write something to the terminal using the printf() function. The only thing that might seem a little special here is the \n thing - it's an escape sequence that outputs a newline.


Once you're done typing the above, press ESC in vi to go back to command mode. Then type :wq and press enter - this saves the file (w) and quits (q).

Back in the terminal, type the following command to compile the code in hello.c:

gcc hello.c -o hello

The -o part means that the next argument (in this case "hello") is the name of the executable to be produced by gcc. On Linux, executables don't need to have extensions such as .exe, although it's perfectly fine to include them to make it easier to recognise them.


Finally, type ./hello and press ENTER to run the program. You should see "Hello world!" as the output, as above.

Note: just in case you can't run the program because of some permissions, try the following command:

chmod 777 hello

Great! This simple tutorial showed how to write C code using the vi editor, compile it using the gcc program, and execute it from within a Linux shell. Come back for more tutorials!