theDevBrent

SDL Project Setup

TLDR;

If you want to skip all of this you can create a project from the template here: sdl-template

One of the biggest pains of getting a new C++ project setup is getting it to a point where you don’t have to think about how it’s being built and can just focus on the code. Languages like Rust, Python, and (unfortunately) JavaScript can have you up and running with just a few commands. This makes it easy for you to start creating small/medium-sized projects rather quickly.

Today we are going to start a C++ and SDL2 project in just a few minutes to get you up and running. We will be using CMake to build the project. This example is a very simple one. We just have one main.cpp source file and one .png asset. In later posts, we will go through how to expand on this structure for a bigger project.

For now, we will get started by getting things set up.

Prerequisites

You will need at least a few things installed:

  1. (git)[https://git-scm.com]
  2. (CMake)[https://cmake.org]
  3. (Ninja) [https://ninja-build.org]

If you don’t have these installed, you should. If you can’t figure out how to install them, then a career in Tech Twitter might be for you.

Let’s get started

First things first let’s get the folder structure set up for us. We are going to keep it simple enough to get started quickly but configurable enough to expand it later if we need to.

- SDL2Project
    - assets
    - external
    - src

For the lazy:

mkdir SDL2Project && cd SDL2Project && mkdir assets && mkdir external && mkdir src && cd ..

Next, we need to init the git:

git init

Add the external libraries via git submodules.

git submodule add https://github.com/libsdl-org/SDL.git external/sdl
git submodule add https://github.com/libsdl-org/SDL_ttf.git external/sdl-ttf
git submodule add https://github.com/libsdl-org/SDL_mixer.git external/sdl-mixer
git submodule add https://github.com/libsdl-org/SDL_image.git external/sdl-image
git submodule add  https://github.com/g-truc/glm.git external/glm

git submodule update --init --recursive

Now for the real fun. Let’s checkout the correct branch for each submodule

cd external/sdl 
git checkout SDL2

cd ../sdl-ttf
git checkout SDL2

cd ../sdl-mixer
git checkout SDL2

cd ../sdl-image
git checkout SDL2

On to the fun

Now that we have that out of the way let’s get on to the star of the show, CMake.

At the root of our project, we need to create a new CMakeLists.txt file. Add the contents below to it.

# The minimum version of CMake required
cmake_minimum_required(VERSION 3.20)

# override some default CMake variables
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Set the name of our project
project(CppSDLTemplate CXX)

# Name of our executable
add_executable(main)
set_target_properties(main PROPERTIES OUTPUT_NAME ${CMAKE_PROJECT_NAME})

# Copy our assets folder to the build folder the  variable will be set by the build command later
add_custom_command(TARGET main POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
    ${CMAKE_SOURCE_DIR}/assets
    $/assets
)

# Add our src and external directories
add_subdirectory("src")
add_subdirectory("external")

Now we need to add another CMakeLists.txt in our /src folder

target_sources(main PRIVATE
    "main.cpp"
)

Now for the big one. Add one more CMakeLists.txt in the /external directory

set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries" FORCE)

#sdl
add_subdirectory(sdl)
target_link_libraries(main SDL2::SDL2main SDL2::SDL2-static)

#sdl image
add_subdirectory(sdl-image)
target_link_libraries(main SDL2_image::SDL2_image-static)

#sdl ttf
set( SDL2TTF_SAMPLES OFF CACHE BOOL "" FORCE )
set( SDL2TTF_INSTALL OFF CACHE BOOL "" FORCE )
set( SDL2TTF_VENDORED ON CACHE BOOL "" FORCE )
set( SDL2TTF_HARFBUZZ ON CACHE BOOL "" FORCE )
add_subdirectory(sdl-ttf)
target_link_libraries(main SDL2_ttf::SDL2_ttf-static)

#sdl mixer
set( SDL2MIXER_SAMPLES OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_INSTALL OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_VENDORED ON CACHE BOOL "" FORCE )
set( SDL2MIXER_DEPS_SHARED OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_FLAC OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_MOD OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_MP3 OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_MIDI OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_OPUS OFF CACHE BOOL "" FORCE )
add_subdirectory(sdl-mixer)
target_link_libraries(main SDL2_mixer::SDL2_mixer-static)

#glm
target_include_directories(main SYSTEM PRIVATE "glm")

The end

It’s time to finally build the beast.

Create a main.cpp in the src directory:

#include 
#include 
#include 

int main() {
  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    std::cout << "Failed to init the SDL2 \n";
    return -1;
  }

  SDL_Window* window = SDL_CreateWindow("It Opened", SDL_WINDOWPOS_CENTERED,
                                        SDL_WINDOWPOS_CENTERED, 400, 400, 0);
  if (!window) {
    std::cout << "Failed to create window\n";
    return -1;
  }

  SDL_Surface* window_surface = SDL_GetWindowSurface(window);
  if (!window_surface) {
    std::cout << "Failed to get the surface from the window\n";
    return -1;
  }

  SDL_Surface* image = IMG_Load("assets/");
  if (!image) {
    std::cout &lt;< "Failed to load image\n";
    return -1;
  }

  bool keep_window_open = true;
  while (keep_window_open) {
    SDL_Event e;
    while (SDL_PollEvent(&e) > 0) {
      switch (e.type) {
        case SDL_QUIT:
          keep_window_open = false;
          break;
      }

      SDL_BlitSurface(image, NULL, window_surface, NULL);
      SDL_UpdateWindowSurface(window);
    }
  }
}

NOTE: Make sure to change the path to the image to the name of your file

Building Time

Let’s build this beast.

cmake -B build -G "Ninja Multi-Config"

Note: The Multi-Config option here lets us choose “Release” or “Debug” when building

Now run:

cmake --build build --config Debug 

OR

cmake --build build --config Release 

Conclusion

You should now have your app built in either the build/Debug/ directory or the build/Debug directory based on which command you ran.

Proudly powered by WordPress