Wednesday, July 11, 2012

Lesson 1: Hello World!

Deprecation Notice:

I've been updating the lessons now that SDL2 is officially released, please visit my new site on Github that has updated lessons and improved code.


In this lesson we will learn a simple method for drawing a bmp image to a screen, the image below to be specific.

You can download the image above by right clicking and selecting save-as. The link is a direct link to the image on the Github repository I have created and as such will be a true BMP image that SDL can load. The repository is also home to all my code from the tutorials and any related assets they need. If you ever lose the assets or want to take a peak at my code, grab it here. But never copy!

The first step as always is to include the SDL header
#include "SDL.h"
Note that depending on your SDL configuration you, Linux users to be specific, may need to do
#include "SDL/SDL.h"
//or
#include "SDL2/SDL.h"
//depending on your configuration
Unless you're specifying the full path to your header files in your flags (Linux users)

First we'll need to start up SDL so that we can use it, note that if SDL fails to initialize it will return -1, in which case we'll want to print out the error using SDL_GetError() and exit our program.

Special note for Visual Studio users: If you've set your System to Windows in your Linker options panel you won't get std out to console, to get this you must change your System to Console.
Next we'll need to create a window that we can draw things too, we can do this by using the SDL_Window:
The SDL_CreateWindow function takes care of making our window and returns a SDL_Window pointer back to us. The first parameter is the name we want for our window, followed by the x,y position we want to open it up at followed by the width and height we want our window to be. The last parameter are various flags we may want for our window, in this case we want it to pop up immediately, so we pass SDL_WINDOW_SHOWN.

We also take care of providing some error safety in that we initialize our pointer as a nullptr and then check to see if it's still null after trying to create the window. If creating the window failed it would still be null and as such we'd want to break out of program. It is important that you always initialize your pointers to NULL, or with the new C++11 standard to nullptr.

Now just opening up a window isn't going to do very much for us, we'll need something to render things to the window as well, so let's get an SDL_Renderer up and running.
Our renderer is created by SDL_CreateRender, which requires a window to render too. We can also specify a video driver to select, or put -1 to have SDL select the appropriate driver based on which is able to support the flags we specify. This is probably the best option to use, as you let SDL take care of picking the right driver for your needs, ie. the flags you pass as the last parameter.

In this case our flags are SDL_RENDERER_ACCELERATED because we want to use a hardware accelerated renderer, ie. the graphics card and SDL_RENDERER_PRESENTVSYNC because we want the SDL_RendererPresent function, which refreshes the screen to be run in sync with the monitor refresh rate.

Note that we use the same error checking method that we used when creating the window

It's time to load an image to draw to the screen! You should have downloaded the image from the Github repository and saved it in the same folder, or nearby to where your executable will be built too.

Although SDL 2.0 uses SDL_Textures for hardware accelerated rendering, we'll still need to load our image to an SDL_Surface using SDL_LoadBMP, as this lesson isn't using the fantastic SDL_image extension library (we'll get to it soon).
Note that you will need to change the filepath passed to SDL_LoadBMP to match the location of the image on your machine, or leave it the same if you've decided to follow my folder structure exactly.

To take advantage of hardware accelerated rendering we must next convert our SDL_Surface to an SDL_Texture that the renderer can draw.
We also free the SDL_Surface at this point because it is no longer needed.

We can now draw our texture to the renderer. First we clear the screen with SDL_RenderClear, then we can draw the texture with SDL_RenderCopy. Finally we update the screen with SDL_RenderPresent.
We also pass two NULL values to RenderCopy, the first one is a pointer to the source rectangle, ie. a clip to take of the image sheet while the second is a pointer to the destination rectangle. By passing NULL to both parameters we tell SDL to take the whole image (first NULL) and draw it at 0, 0 and stretch it to fill the entire screen (second NULL), more on this later.

We also tell our program to wait for 2000milliseconds with SDL_Delay so that we can see the screen. Without the delay the window would pop up and then close as the program finishes very quickly.
Before we exit our program it is necessary to free the memory used by our window, renderer and texture. This is done using the various SDL_Destroy functions
Finish the program by quitting SDL, and returning 0.
Compile the program and check it out! Don't forget to put SDL.dll in the same directory as your executable or you'll get an error pop-up. If you're using Linux you should already have the shared libraries installed in your path so you shouldn't have any issues

Congratulations on your first SDL 2.0 program!


Troubleshooting

If your program fails to compile make sure you've properly configured your libraries and linked to the correct path in your include statement.

If your program complains about SDL.dll missing, make sure it is located in the same folder as the executable.

If your program runs but exits with out displaying anything make sure your image path is set correctly. If that doesn't help try writing some cout or file output into the program, although depending on your platform and configuration settings cout may not appear.

End of Lesson 1

That does it for Lesson 1, I'll see you again soon in Lesson 2: Don't Put Everything in Main

26 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Linux users to be specific, may need to do

    #include "SDL2/SDL.h"

    ReplyDelete
  3. Question: I'm doing this tutorial in Visual Studio 2010, and I'm still not great with it. When I try to "start debugging" it says it couldn't open the Hello.bmp file, but when I go to the target directory where the exe is and run it there, it shows up fine. Why does this happen?

    ReplyDelete
    Replies
    1. When you run in VS with debugging it actually runs the project in the folder ProjectName/Debug(or Release)/. There may be a way to change this, I should actually look into it sometime myself heh. Although it seems with my projects using relative filepaths my projects are able to run with/without debugging.

      Delete
    2. Oh actually no, I was misreading the output window haha, it does run it from the normal build directory. I'm not sure what's going on, sorry.

      Delete
    3. When you debug a program, VS 2010 opens the .exe that is located in directory Projectname/bin/Debug/. So the picture should be located there, if you want the VS to find it.

      Delete
  4. It's necessary to #include to be able to use std::cout and std::endl.

    Do you mention somewhere what your overall folder structure is, and why you use it instead of putting hello.bmp at the location that Visual Studio uses as the default path if you don't specify one in the code?

    Also, as a style note it seems weird to me to initialize variables to nullptr and then immediately assign them to the result of a function call (which will always return something, even if that something is null), instead of doing it all at once - e.g.:

    SDL_Surface* bmp(SDL_LoadBMP("hello.bmp"));

    ReplyDelete
    Replies
    1. I try to only show code that's new or changed in the lesson text, ie. stuff like includes is pretty obvious but if needed can be looked up in the Github repo (linked on the sidebar).

      The code posted uses a different folder structure than the code in the repository, but you can use whatever folder layout you prefer, as long as you change the file paths accordingly.

      The initialization is typically done to prevent dangling pointers, but you're right SDL_LoadBMP will return NULL if loading fails, so that can be used for initializing. I'll update the code when I get a chance heh.

      Thanks for the feedback!

      Delete
  5. How do I load the YUV format data to a surface and display on the screen suruface?
    Like the SDL_CreateYUVOverlay function in SDL 1.2, I can set the pixel value in SDL_overlay.
    The SDL 2.0 do not have any YUV Overlay functions.

    Is the only way convert the YUV format to RGB format?

    ReplyDelete
    Replies
    1. I'm not sure, I haven't tried using YUV formatted data in SDL before. Maybe browse through the 2.0 docs or head to the SDL irc channel, #sdl on freenode.

      Delete
  6. I'm using DevC++ and nullptr doesn't work, is it ok to just use NULL instead?

    ReplyDelete
    Replies
    1. I'd recommend you stop using DevC++, it's pretty outdated. Something like Code::Blocks or Visual Studio 2012 will be a lot better. nullptr itself is a C++11 feature, so you should make sure to have C++11 enabled in your compiler settings, for gcc this is -std=c++11 (or -std=c++0x if an older version) in recent versions of Visual Studio it's enabled by default. If you absolutely insist on sticking with DevC++, then yes NULL would be fine instead.

      Delete
  7. Thanks for the interesting tutorial, but I am unable to start the main with even very simple printf("Hello world");
    On windows 7, I am receiving the error: MyFirstApp has stopped working as if there is a segmentation fault or something like that.

    This is my code, running on Pelles C:

    #include
    #include

    int main(int argc, char **argv)
    {
    if (SDL_Init(SDL_INIT_EVERYTHING) == -1){
    printf("Error\n");
    }
    else{
    printf("OK\n");
    }
    return 0;
    }

    ReplyDelete
    Replies
    1. The code looks ok to me, are you sure the SDL2 dll is in the same folder as your executable? I've never heard of Pelles C so if it's an issue related to that I'm not sure.

      Delete
  8. Great tutorial, thanks for writing it :)
    I've made my first non-console program!

    ReplyDelete
  9. Hi man great tutorial but I've had some problems. Even before i had change the subsystem on Linker to Console it's still accoring this errors :
    hellowsdl2\hellowsdl2\main.cpp(5): error C2039: 'cout' : is not a member of 'std
    hellowsdl2\hellowsdl2\main.cpp(5): error C2065: 'cout' : undeclared identifier

    and the same for endl... that's it.

    ReplyDelete
    Replies
    1. Did you also #include ? That's cout and endl live. Also, use the new updated tutorials over on github: http://twinklebear.github.io/sdl2%20tutorials/2013/08/17/lesson-1-hello-world/ . The code and lesson text is a lot better.

      Delete
    2. Oh i guess it decided to cut out the carrots. You need to include iostream.

      Delete
    3. Problem soulved! But now there is another one. Now the window just open and them close again, nothing shows up

      Delete
    4. WoW in the link you post there is a lot of information I didn't know, awesome! And thank your time I'm so noob with this things that I fell bad asking people for help.

      Delete
  10. Nvm, on github there is a guys on comments that had the same problem, according to him I'm putting the wrong way to add the bitmap image, I just don't get how did he fix it, sorry for the poor english I'm from Brazil and in/at (I don't know which one i should use) high school...

    ReplyDelete
    Replies
    1. Hmm, it could be your filepath isn't right, what does SDL_GetError report when it fails? And which comment are you referring to?

      Delete
    2. This comment has been removed by the author.

      Delete
  11. the SDL_GetError report something but i couldn't read it because the window just ope for 1 seg and them close. And the comment is from the first guy that comment and replay himself two times.

    ReplyDelete
    Replies
    1. Oh try running it from the command prompt, or changing your IDE settings to keep the console window open after the program exits so you can see the output.

      Delete
    2. Yeah it looks like the filepath isn't right, I just need to figure out how to fix it...

      Delete