diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index cbb5022..0000000
--- a/src/main.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <SDL2/SDL.h>
-#include <SDL2/SDL_events.h>
-#include <SDL2/SDL_render.h>
-#include <SDL2/SDL_video.h>
-#include <stdbool.h>
-
-#define WINDOW_WIDTH 800
-#define WINDOW_HEIGHT 600
-
-int main(void) {
-  SDL_Init(SDL_INIT_EVERYTHING);
-
-  SDL_Window *window =
-      SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
-                       WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
-
-  SDL_Renderer *renderer = SDL_CreateRenderer(
-      window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
-
-  bool running = true;
-
-  SDL_Event event = {0};
-
-  while (running) {
-    while (SDL_PollEvent(&event)) {
-      switch (event.type) {
-      case SDL_QUIT:
-        running = false;
-        break;
-      }
-    }
-
-    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
-
-    SDL_RenderClear(renderer);
-
-    SDL_RenderPresent(renderer);
-  }
-
-  SDL_DestroyRenderer(renderer);
-
-  SDL_DestroyWindow(window);
-
-  SDL_Quit();
-
-  return 0;
-}
diff --git a/src/main.cc b/src/main.cc
new file mode 100644
index 0000000..2ad9fdb
--- /dev/null
+++ b/src/main.cc
@@ -0,0 +1,107 @@
+#include "SDL_error.h"
+#include "SDL_video.h"
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_events.h>
+#include "glad/glad.h"
+#include <cstdint>
+#include <cstdio>
+#include <stdbool.h>
+
+#define WINDOW_WIDTH 1280
+#define WINDOW_HEIGHT 720
+
+enum exit_codes : int32_t {
+  EXIT_CODE_SUCCESS,
+  EXIT_CODE_SDL_INIT_FAILED,
+  EXIT_CODE_WINDOW_CREATION_FAILED,
+  EXIT_CODE_OPENGL_CONTEXT_FAILED,
+  EXIT_CODE_GLAD_LOADER_FAILED,
+};
+
+struct App {
+  SDL_Window    *window;
+  SDL_GLContext context;
+  SDL_Event     event;
+};
+
+int  init(App &app);
+void run_main_loop(App &app);
+void cleanup(App &app);
+
+int main() {
+  App app    = {};
+  int result = init(app);
+  if (result != EXIT_CODE_SUCCESS) {
+    return result;
+  }
+
+  run_main_loop(app);
+
+  cleanup(app);
+
+  return EXIT_CODE_SUCCESS;
+}
+
+int init(App &app) {
+  if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
+    fprintf(stderr, "Failed to initialise SDL: %s", SDL_GetError());
+    return EXIT_CODE_SDL_INIT_FAILED;
+  }
+
+  uint32_t flags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI;
+  app.window        = SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+                                    WINDOW_WIDTH, WINDOW_HEIGHT, flags);
+  if (!app.window) {
+    fprintf(stderr, "Failed to create window: %s", SDL_GetError());
+    return EXIT_CODE_WINDOW_CREATION_FAILED;
+  }
+
+  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
+  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
+  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+
+  app.context = SDL_GL_CreateContext(app.window);
+  if (!app.context) {
+    fprintf(stderr, "Failed to create OpenGL context: %s", SDL_GetError());
+    return EXIT_CODE_OPENGL_CONTEXT_FAILED;
+  }
+
+  // Init glad
+  if (!gladLoadGLLoader(SDL_GL_GetProcAddress)) {
+    fprintf(stderr, "Failed to initialise glad");
+    return EXIT_CODE_GLAD_LOADER_FAILED;
+  }
+
+  printf("%s\n%s\n%s\n%s\n",
+         glGetString(GL_VENDOR),
+         glGetString(GL_RENDERER),
+         glGetString(GL_VERSION),
+         glGetString(GL_SHADING_LANGUAGE_VERSION)
+  );
+
+  return EXIT_CODE_SUCCESS;
+}
+
+void run_main_loop(App &app) {
+  bool running = true;
+
+  while (running) {
+    while (SDL_PollEvent(&app.event)) {
+      switch (app.event.type) {
+      case SDL_QUIT:
+        running = false;
+        break;
+      }
+    }
+
+    SDL_GL_SwapWindow(app.window);
+  }
+}
+
+void cleanup(App &app) {
+  SDL_GL_DeleteContext(app.context);
+  SDL_DestroyWindow(app.window);
+  SDL_Quit();
+}