Code Sampe – SDL + OpenGL App

//START OF HEADER FILE (INTERFACE)
//----------------------------------------------------------

class App
{
  public:

    Signal<void, unsigned, unsigned> OnResized;
    Signal<void>                     OnActivated;
    Signal<void>                     OnDeactivated;
    Signal<void>                     OnQuit;
    
    App(unsigned width = 800, unsigned height = 600);
    virtual ~App(void);
    int Execute(void);
    
    //metrics
    unsigned Width (void) const;
    unsigned Height(void) const;
    
    //input
    const InputState &Input(void) const;

  protected:

    virtual void Init(void);
    virtual void Update(float dt);
    virtual void Render(float dt);
    virtual void CleanUp(void);
    
    void SwapBuffers(void);
    void Exit(void);

  private:
    
    void SDLEvent(SDL_Event *e);
    bool SDLInit(void);
    
    //video data
    bool         m_isRunning;
    SDL_Surface *m_display;
    
    //metrics
    unsigned m_width, m_height;
    
    //input state
    InputState m_input;
};

//----------------------------------------------------------
//END OF HEADER FILE


//START OF SOURCE FILE (IMPLEMENTATION)
//----------------------------------------------------------

App::App(unsigned width, unsigned height)
  : m_width(width), m_height(height)
  , m_isRunning(false)
  , m_display(nullptr)
{
  m_input.WindowSize(m_width, m_height);
}

App::~App(void) { }

int App::Execute(void)
{
  if (!SDLInit())
    return -1;

  SDL_Event e;

  Init();

  //start main loop
  Stopwatch stopwatch;
  stopwatch.Start();
  m_isRunning = true;
  while (m_isRunning)
  {
    //handle events
    while (SDL_PollEvent(&e))
      SDLEvent(&e);

    //record delta time
    float dt = stopwatch.Stop();
    stopwatch.Start();

    //update input
    m_input.Update();

    //update loop
    Update(dt);

    //render loop
    Render(dt);
  }

  CleanUp();

  return 0;
}

unsigned App::Width (void) const { return m_width ; }
unsigned App::Height(void) const { return m_height; }

const InputState & App::Input(void) const
{ return m_input; }

void App::Init(void)
{ }

void App::Update(float dt)
{ }

void App::Render(float dt)
{ }

void App::CleanUp(void)
{ }

void App::SwapBuffers(void)
{
  SDL_GL_SwapBuffers();
}

void App::Exit(void)
{
  m_isRunning = false;
}

void App::SDLEvent(SDL_Event *e)
{
  switch (e->type)
  {
    //input events
    //------------------------------------------
    
    //mouse move
    case SDL_MOUSEMOTION:
    {
      SDL_MouseMotionEvent * mme = 
        reinterpret_cast<SDL_MouseMotionEvent *>(e);
      m_input.MoveMouse(mme->x, mme->y);
      break;
    }

    //mouse button down
    case SDL_MOUSEBUTTONDOWN:
    {
      SDL_MouseButtonEvent * mbe = 
        reinterpret_cast<SDL_MouseButtonEvent *>(e);
      switch (mbe->button)
      {
        case InputCode::MOUSE_BUTTON_LEFT:
          m_input.IsPressed(InputCode::MOUSE_BUTTON_LEFT);
          break;
        case InputCode::MOUSE_BUTTON_RIGHT:
          m_input.IsPressed(InputCode::MOUSE_BUTTON_RIGHT);
          break;
      }
      break;
    }
    
    //mouse button up
    case SDL_MOUSEBUTTONUP:
    {
      SDL_MouseButtonEvent * mbe = 
        reinterpret_cast<SDL_MouseButtonEvent *>(e);
      switch (mbe->button)
      {
        case InputCode::MOUSE_BUTTON_LEFT:
          m_input.IsReleased(InputCode::MOUSE_BUTTON_LEFT);
          break;
        case InputCode::MOUSE_BUTTON_RIGHT:
          m_input.IsReleased(InputCode::MOUSE_BUTTON_RIGHT);
          break;
      }
      break;
    }

    //keyboard key down
    case SDL_KEYDOWN:
    {
      //TODO
      break;
    }

    //keyboard key up
    case SDL_KEYUP:
    {
      //TODO
      break;
    }

    //window events
    //------------------------------------------

    //video resize
    case SDL_VIDEORESIZE:
    {
      SDL_ResizeEvent * re = 
        reinterpret_cast<SDL_ResizeEvent *>(e);
      m_width = re->w; m_height= re->h;
      m_input.WindowSize(m_width, m_height);

      OnResized.Dispatch(m_width, m_height);

      //TODO: fullscreen GL re-init

      glViewport(0, 0, m_width, m_height);
      break;
    }

    //system events
    //------------------------------------------

    //gain/lose focus
    case SDL_ACTIVEEVENT:
    {
      SDL_ActiveEvent * ae = 
        reinterpret_cast<SDL_ActiveEvent *>(e);
      if (ae->gain) OnActivated  .Dispatch();
      else          OnDeactivated.Dispatch();
      break;
    }

    //quit message
    case SDL_QUIT:
    {
      OnQuit.Dispatch();
      Exit();
      break;
    }
  }
}

bool App::SDLInit(void)
{
  if(SDL_Init(SDL_INIT_EVERYTHING) < 0)
    return false;

  //SDL attributes have to be set 
  //BEFORE calling SDL_SetVideoMode
  SDL_GL_SetAttribute(SDL_GL_RED_SIZE  , 8);
  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE , 8);
  SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);

  SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE  , 8);
  SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 8);
  SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE , 8);
  SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 8);

  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE , 32);
  SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);

  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);

  //init SDL surface
  m_display = 
    SDL_SetVideoMode
    (
      m_width, m_height, 32, 
        SDL_HWSURFACE 
      | SDL_DOUBLEBUF 
      | SDL_OPENGL 
      | SDL_RESIZABLE
    );

  if(!m_display)
    return false;

  //init OpenGL
  glViewport(0, 0, m_width, m_height);
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glClearDepth(1.0f);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);

  //init GLEW
  glewInit();

  //print OpenGL info
  std::cout << "OpenGL version: " 
            << glGetString(GL_VERSION) 
            << std::endl << std::endl;

  return true;
}

//----------------------------------------------------------
//END OF SOURCE FILE

Leave a Reply