Skip to content

Instantly share code, notes, and snippets.

@nilium
Created February 18, 2013 11:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nilium/4976671 to your computer and use it in GitHub Desktop.
Save nilium/4976671 to your computer and use it in GitHub Desktop.
Example main.cc file for using libdispatch and GLFW together on Mac OS X.
#include <atomic>
#include <stdexcept>
#ifdef TARGET_OS_MAC
#include <dispatch/dispatch.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
#endif
#include <gl/glfw3.h>
#include <pthread.h>
// Main queue - used for GLFW calls and event pumping
static dispatch_queue_t g_main_queue;
// Frame loop running bool (uses atomic<bool> instead of atomic_bool because
// libc++ doesn't provide an atomic_bool yet)
static std::atomic<bool> g_frameloop_running { true };
// Does what it says
static void sys_terminate(void *ctx);
// Handles frame logic and sends rendering tasks to the GL queue (or just does
// the rendering itself)
static void *sys_frameloop(void *ctx);
// Main routine - initializes stuff & kicks off the frame loop
static void sys_initialize(void *ctx);
// Tells the main loop to quit. Thread-safe.
static void sys_quit();
int main(int argc, char const *argv[])
{
// Bootstrap
#ifdef TARGET_OS_MAC
// Play nice with ARC even if ARC isn't enabled (it isn't for this unit).
@autoreleasepool {
#endif
g_main_queue = dispatch_get_main_queue();
// Queue up the actual main routine
dispatch_async_f(g_main_queue, NULL, sys_initialize);
#ifdef TARGET_OS_MAC
// On OS X, do NOT call dispatch_main, as this will terminate thread 0 (the UI
// thread), causing all manner of hell to break loose when you attempt to
// create a window. Instead, use NSRunLoop to kick off the main run-loop,
// which in turn keeps the main dispatch queue on thread 0 and allows OS X's
// UI to function as intended.
[[NSRunLoop mainRunLoop] run];
} // @autoreleasepool
#else
// Other OSes may require their own unique bootstrapping.
dispatch_main();
#endif
return 0;
}
// must be run on main queue
static void sys_initialize(void *ctx)
{
pthread_t frame_thread;
pthread_attr_t thread_attr;
GLFWwindow *window = nullptr;
if (glfwInit()) {
atexit(glfwTerminate);
} else {
throw std::runtime_error("Failed to initialize GLFW");
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
window = glfwCreateWindow(800, 600, "Snow", NULL, NULL);
if (!window) {
throw std::runtime_error("Failed to create GLFW window");
}
// Launch frameloop thread - do not just call sys_frameloop because we want to
// keep the main queue unblocked -- it has to be free so we can poll for
// events and so on later.
if (pthread_attr_init(&thread_attr)) {
throw std::runtime_error("Failed to init frame thread attributes");
}
if (pthread_create(&frame_thread, &thread_attr,
sys_frameloop, static_cast<void *>(window))) {
throw std::runtime_error("Failed to start frame loop thread");
}
pthread_attr_destroy(&thread_attr);
}
static void sys_quit()
{
bool from = g_frameloop_running;
while (!g_frameloop_running.compare_exchange_weak(from, false));
}
// Run as single thread
static void *sys_frameloop(void *ctx)
{
GLFWwindow *window = static_cast<GLFWwindow *>(ctx);
// Make this thread own the window's GL context.
glfwMakeContextCurrent(window);
// Initialize GL here
#warning TODO: Initialize OpenGL
while (g_frameloop_running) {
// Poll events from the main thread. You'll likely want to do this using
// dispatch_sync instead of dispatch_async.
dispatch_sync(g_main_queue, [] { glfwPollEvents(); });
// Update game, handle events, etc. - presumably you have a thread-safe way
// of doing this. It's not hard, I've already done it, so I can guarantee
// it's easy enough. You might want to push this off to yet another thread
// or use dispatch queues to handle it asynchronously though. Depends on
// what you're doing. At some point, call sys_quit to kill the frame loop.
#warning TODO: Update game logic
glClear(GL_COLOR_BUFFER_BIT);
#warning TODO: Render game scene
glfwSwapBuffers(window);
} // while (running)
// Go back to the main thread and kill the program cleanly.
dispatch_async_f(g_main_queue, window, sys_terminate);
return NULL;
}
// must be run on main queue
static void sys_terminate(void *ctx)
{
if (ctx) {
glfwDestroyWindow((GLFWwindow *)ctx);
}
exit(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment