1 module window; 2 3 /** 4 Contains various helpers, common code, and initialization routines. 5 */ 6 7 import std.algorithm : min; 8 import std.exception : enforce; 9 import std.functional : toDelegate; 10 import std.stdio : stderr; 11 import std..string : format; 12 13 import deimos.glfw.glfw3; 14 15 import glad.gl.enums; 16 import glad.gl.ext; 17 import glad.gl.funcs; 18 import glad.gl.loader; 19 import glad.gl.types; 20 21 import glwtf.input; 22 import glwtf.window; 23 24 /// init 25 shared static this() 26 { 27 enforce(glfwInit()); 28 } 29 30 /// uninit 31 shared static ~this() 32 { 33 glfwTerminate(); 34 } 35 36 /// 37 enum WindowMode 38 { 39 fullscreen, 40 windowed, 41 } 42 43 /** 44 Create a window, an OpenGL 3.x context, and set up some other 45 common routines for error handling, window resizing, etc. 46 */ 47 Window createWindow(string windowName, WindowMode windowMode = WindowMode.windowed, int width = 1024, int height = 768) 48 { 49 auto vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); 50 51 // constrain the window size so it isn't larger than the desktop size. 52 width = min(width, vidMode.width); 53 height = min(height, vidMode.height); 54 55 // set the window to be initially inivisible since we're repositioning it. 56 glfwWindowHint(GLFW_VISIBLE, 0); 57 58 // enable debugging 59 glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1); 60 61 Window window = createWindowContext(windowName, WindowMode.windowed, width, height); 62 63 // center the window on the screen 64 glfwSetWindowPos(window.window, (vidMode.width - width) / 2, (vidMode.height - height) / 2); 65 66 // glfw-specific error routine (not a generic GL error handler) 67 register_glfw_error_callback(&glfwErrorCallback); 68 69 // anti-aliasing number of samples. 70 window.samples = 4; 71 72 // activate an opengl context. 73 window.make_context_current(); 74 75 // load all OpenGL function pointers via glad. 76 enforce(gladLoadGL()); 77 78 enforce(glGenBuffers !is null); 79 80 // only interested in GL 3.x 81 enforce(GLVersion.major >= 3); 82 83 // turn v-sync off. 84 glfwSwapInterval(0); 85 86 version (OSX) 87 { 88 // GL_ARM_debug_output and GL_KHR_debug are not supported under OS X 10.9.3 89 } 90 else 91 { 92 // ensure the debug output extension is supported 93 enforce(GL_ARB_debug_output || GL_KHR_debug); 94 95 // cast: workaround for 'nothrow' propagation bug (haven't been able to reduce it) 96 auto hookDebugCallback = GL_ARB_debug_output ? glDebugMessageCallbackARB 97 : cast(typeof(glDebugMessageCallbackARB))glDebugMessageCallback; 98 99 100 // hook the debug callback 101 // cast: when using derelict it assumes its nothrow 102 hookDebugCallback(cast(GLDEBUGPROCARB)&glErrorCallback, null); 103 104 // enable proper stack tracing support (otherwise we'd get random failures at runtime) 105 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); 106 } 107 108 // finally show the window 109 glfwShowWindow(window.window); 110 111 return window; 112 } 113 114 /** Create a window and an OpenGL context. */ 115 Window createWindowContext(string windowName, WindowMode windowMode, int width, int height) 116 { 117 auto window = new Window(); 118 auto monitor = windowMode == WindowMode.fullscreen ? glfwGetPrimaryMonitor() : null; 119 auto context = window.create_highest_available_context(width, height, windowName, monitor, null, GLFW_OPENGL_CORE_PROFILE); 120 121 // ensure we've loaded a proper context 122 enforce(context.major >= 3); 123 124 return window; 125 } 126 127 /** Just emit errors to stderr on GLFW errors. */ 128 void glfwErrorCallback(int code, string msg) 129 { 130 stderr.writefln("Error (%s): %s", code, msg); 131 } 132 133 /// 134 class GLException : Exception 135 { 136 @safe pure nothrow this(string msg = "", string file = __FILE__, size_t line = __LINE__, Throwable next = null) 137 { 138 super(msg, file, line, next); 139 } 140 141 @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) 142 { 143 super(msg, file, line, next); 144 } 145 } 146 147 /** 148 GL_ARB_debug_output or GL_KHR_debug callback. 149 150 Throwing exceptions across language boundaries is ok as 151 long as $(B GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) is enabled. 152 */ 153 extern (System) 154 private void glErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, in GLchar* message, GLvoid* userParam) 155 { 156 //string msg = format("glErrorCallback: source: %s, type: %s, id: %s, severity: %s, length: %s, message: %s, userParam: %s", 157 // source, type, id, severity, length, message.to!string, userParam); 158 159 //stderr.writeln(msg); 160 }