Eric Nething

Game Programming: Setup

Welcome to the first part of my Game Programming in Haskell series! I assume that you have basic knowledge of Haskell, but no familiarity with game programming. I will show you how to construct a simple game using only SDL2 and OpenGL.

We will use SDL to handle input from the player and audio output, and OpenGL to handle graphics rendering.

In the following code, all functions from SDL are qualified as SDL, and all SDL constants begin with SDL_.

All functions from OpenGL are of the form glFunctionName, and all OpenGL constant begin with GL_.

Basic Structure

We need a few imports to get started.

-- OpenGL
import           Graphics.GL

-- SDL2
import qualified Graphics.UI.SDL as SDL

-- SDL2 Constants
import           Graphics.UI.SDL.Enum as SDL

-- Foreign Function Interface (FFI)
import Foreign
import Foreign.C

All of the following are contained in main.

main :: IO ()
main = do

Initialize all subsystems and create a window.

  • SDL.init initializes SDL with the given flags (Multiple flags must be bitwise OR-ed together using .|. from Data.Bits)
  • withCString is used to marshal a Haskell String into a C String
  • SDL.createWindow creates a window when given: title, x-position, y-position, width, height, and window-flags
SDL.init SDL_INIT_EVERYTHING

window <- withCString "gl and sdl2 basics" $ \t ->
  SDL.createWindow t 0 0 800 600 SDL_WINDOW_SHOWN

Set the options for the OpenGL rendering context, then create the context.

We set the profile to Core and the version to 3.2 (you may need to change the version based on your graphics card). We enable double buffering and set the depth buffer size to 24.

SDL.glSetAttribute SDL_GL_CONTEXT_PROFILE_MASK SDL_GL_CONTEXT_PROFILE_CORE
SDL.glSetAttribute SDL_GL_CONTEXT_MAJOR_VERSION 3
SDL.glSetAttribute SDL_GL_CONTEXT_MINOR_VERSION 2

SDL.glSetAttribute SDL_GL_DOUBLEBUFFER 1
SDL.glSetAttribute SDL_GL_DEPTH_SIZE 24

renderer <- SDL.glCreateContext window

Perform initial set-up for any other resources, then start the main game loop.

game <- initResources initialGameState
  
loop window Set.empty game

When the loop ends, we need to perform some clean up before exiting. Destroy the rendering context, destroy the window, and terminate SDL.

SDL.glDeleteContext renderer
SDL.destroyWindow window
SDL.quit

Rendering Pipeline