1 module unecht.glfw.glfwwindow; 2 3 import std.stdio; 4 5 import derelict.glfw3.glfw3; 6 7 import unecht.ue; 8 import unecht.core.types; 9 import unecht.core.window; 10 import unecht.core.events; 11 12 /// 13 class GlfwWindow : UEWindow 14 { 15 private: 16 /// framebuffer size 17 UESize size; 18 /// actual window size 19 UESize _windowSize; 20 /// 21 UEEvents _events; 22 /// 23 double _lastMousePosX = 0; 24 /// 25 double _lastMousePosY = 0; 26 27 package: 28 29 /// 30 public @property bool isRetina() const { return size.width > _windowSize.width && size.height > _windowSize.height; } 31 /// 32 public @property bool shouldClose() { return glfwWindowShouldClose(glfwWindow)!=0; } 33 /// 34 public @property GLFWwindow* window() { return glfwWindow; } 35 /// 36 public @property void* windowPtr() { return glfwWindow; } 37 /// 38 public @property UESize windowSize() const { return _windowSize; } 39 /// 40 public @property UESize framebufferSize() const { return size; } 41 42 /// 43 bool create(UESize _size, string _title, UEEvents _evs) 44 { 45 import std.string:toStringz; 46 47 _events = _evs; 48 49 //TODO: support multisampling 50 //glfwWindowHint(GLFW_SAMPLES, 4); 51 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true); 52 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 53 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 54 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 55 56 glfwWindow = glfwCreateWindow( 57 _size.width, 58 _size.height, 59 toStringz(_title), null, null); 60 61 if (!glfwWindow) 62 return false; 63 64 glfwSetWindowUserPointer(glfwWindow, cast(void*)this); 65 glfwMakeContextCurrent(glfwWindow); 66 67 int w,h; 68 glfwGetFramebufferSize(glfwWindow, &w, &h); 69 size = UESize(w,h); 70 71 glfwGetWindowSize(glfwWindow, &w, &h); 72 _windowSize = UESize(w,h); 73 74 //TODO: support for fixed updates befor disabling vsync 75 //glfwSwapInterval(0); 76 glfwSwapInterval(1); 77 78 glfwSetCursorPosCallback(glfwWindow, &cursor_pos_callback); 79 glfwSetMouseButtonCallback(glfwWindow, &mouse_button_callback); 80 glfwSetKeyCallback(glfwWindow, &key_callback); 81 glfwSetWindowSizeCallback(glfwWindow, &wnd_size_callback); 82 glfwSetCharCallback(glfwWindow, &character_callback); 83 glfwSetFramebufferSizeCallback(glfwWindow, &framebuffer_size_callback); 84 glfwSetWindowFocusCallback(glfwWindow, &window_focus_callback); 85 glfwSetScrollCallback(window, &mouse_scroll_callback); 86 87 return true; 88 } 89 90 /// 91 public bool isCursorPosInside(float x, float y) pure const 92 { 93 static immutable border = 1; 94 95 return x > border && 96 y > border && 97 x < _windowSize.width - border && 98 y < _windowSize.height - border; 99 } 100 101 /// 102 public void wrapAroundCursorPos(float x, float y) 103 { 104 static immutable border = 3; 105 106 auto newx = cast(int)x % (_windowSize.width - border); 107 auto newy = cast(int)y % (_windowSize.height - border); 108 109 if(x < border) 110 newx = _windowSize.width - border + cast(int)x; 111 if(y < border) 112 newy = _windowSize.height - border + cast(int)y; 113 114 glfwSetCursorPos(glfwWindow, newx, newy); 115 } 116 117 /// 118 void showCursor(bool _show) 119 { 120 glfwSetInputMode(glfwWindow, GLFW_CURSOR, _show?GLFW_CURSOR_NORMAL:GLFW_CURSOR_HIDDEN); 121 } 122 123 /// 124 void destroy() 125 { 126 glfwDestroyWindow(glfwWindow); 127 } 128 129 /// 130 void close() 131 { 132 glfwSetWindowShouldClose(glfwWindow, true); 133 } 134 135 /// 136 void swapBuffers() 137 { 138 glfwSwapBuffers(glfwWindow); 139 } 140 141 /// 142 void onResize(UESize size) 143 { 144 _windowSize = size; 145 } 146 147 /// 148 private void glfwOnKey(int key, int scancode, int action, int mods) nothrow 149 { 150 UEEvent ev; 151 ev.eventType = UEEventType.key; 152 ev.keyEvent.key = cast(UEKey)key; 153 ev.keyEvent.action = UEEvent.KeyEvent.Action.Down; 154 155 if(action == GLFW_RELEASE) 156 ev.keyEvent.action = UEEvent.KeyEvent.Action.Up; 157 else if(action == GLFW_REPEAT) 158 ev.keyEvent.action = UEEvent.KeyEvent.Action.Repeat; 159 160 ev.keyEvent.mods.setFromBitMaskGLFW(mods); 161 162 _events.trigger(ev); 163 } 164 165 /// 166 private void glfwOnChar(uint codepoint) nothrow 167 { 168 UEEvent ev; 169 ev.eventType = UEEventType.text; 170 ev.textEvent.character = cast(dchar)codepoint; 171 172 populateCurrentKeyMods(ev.textEvent.mods); 173 174 _events.trigger(ev); 175 } 176 177 /// 178 private void glfwOnMouseMove(double x, double y) nothrow 179 { 180 UEEvent ev; 181 ev.eventType = UEEventType.mousePos; 182 ev.mousePosEvent.x = _lastMousePosX = x; 183 ev.mousePosEvent.y = _lastMousePosY = y; 184 185 populateCurrentKeyMods(ev.mousePosEvent.mods); 186 187 _events.trigger(ev); 188 } 189 190 /// 191 private void glfwOnMouseButton(int button, int action, int mods) nothrow 192 { 193 UEEvent ev; 194 ev.eventType = UEEventType.mouseButton; 195 ev.mouseButtonEvent.button = button; 196 ev.mouseButtonEvent.action = (action == GLFW_PRESS) ? UEEvent.MouseButtonEvent.Action.down : UEEvent.MouseButtonEvent.Action.up; 197 198 //TODO: click detection here instaed of in mouseControls.d 199 ev.mouseButtonEvent.pos.x = _lastMousePosX; 200 ev.mouseButtonEvent.pos.y = _lastMousePosY; 201 202 ev.mouseButtonEvent.pos.mods.setFromBitMaskGLFW(mods); 203 204 _events.trigger(ev); 205 } 206 207 /// 208 private void glfwOnMouseScroll(double xoffset, double yoffset) nothrow 209 { 210 UEEvent ev; 211 ev.eventType = UEEventType.mouseScroll; 212 ev.mouseScrollEvent.xoffset = xoffset; 213 ev.mouseScrollEvent.yoffset = yoffset; 214 215 populateCurrentKeyMods(ev.mousePosEvent.mods); 216 217 _events.trigger(ev); 218 } 219 220 /// 221 private void glfwOnWndSize(int width, int height) nothrow 222 { 223 UEEvent ev; 224 ev.eventType = UEEventType.windowSize; 225 ev.windowSizeEvent.size = UESize(width,height); 226 227 _windowSize = ev.windowSizeEvent.size; 228 229 _events.trigger(ev); 230 } 231 232 /// 233 private void glfwOnFramebufferSize(int width, int height) nothrow 234 { 235 UEEvent ev; 236 ev.eventType = UEEventType.framebufferSize; 237 ev.framebufferSizeEvent.size = UESize(width,height); 238 239 size = ev.framebufferSizeEvent.size; 240 241 _events.trigger(ev); 242 } 243 244 /// 245 private void glfwOnWindowFocus(bool gainedFocus) nothrow 246 { 247 UEEvent ev; 248 ev.eventType = UEEventType.windowFocus; 249 ev.focusEvent.gainedFocus = gainedFocus; 250 251 _events.trigger(ev); 252 } 253 254 /// 255 private void populateCurrentKeyMods(ref EventModKeys mods) nothrow 256 { 257 mods.set(glfwGetKey(glfwWindow, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS, 258 glfwGetKey(glfwWindow, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS, 259 glfwGetKey(glfwWindow, GLFW_KEY_LEFT_ALT) == GLFW_PRESS, 260 glfwGetKey(glfwWindow, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS); 261 } 262 263 private: 264 GLFWwindow* glfwWindow; 265 } 266 267 private nothrow extern(C) 268 { 269 void character_callback(GLFWwindow* window, uint codepoint) 270 { 271 GlfwWindow wnd = cast(GlfwWindow)glfwGetWindowUserPointer(window); 272 wnd.glfwOnChar(codepoint); 273 } 274 275 void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) 276 { 277 GlfwWindow wnd = cast(GlfwWindow)glfwGetWindowUserPointer(window); 278 wnd.glfwOnMouseMove(xpos, ypos); 279 } 280 281 void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) 282 { 283 GlfwWindow wnd = cast(GlfwWindow)glfwGetWindowUserPointer(window); 284 wnd.glfwOnMouseButton(button, action, mods); 285 } 286 287 void mouse_scroll_callback(GLFWwindow* window, double xoffset, double yoffset) 288 { 289 GlfwWindow wnd = cast(GlfwWindow)glfwGetWindowUserPointer(window); 290 wnd.glfwOnMouseScroll(xoffset, yoffset); 291 } 292 293 void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) 294 { 295 GlfwWindow wnd = cast(GlfwWindow)glfwGetWindowUserPointer(window); 296 wnd.glfwOnKey(key,scancode,action,mods); 297 } 298 299 void wnd_size_callback(GLFWwindow* window, int width, int height) nothrow 300 { 301 GlfwWindow wnd = cast(GlfwWindow)glfwGetWindowUserPointer(window); 302 wnd.glfwOnWndSize(width,height); 303 } 304 305 void framebuffer_size_callback(GLFWwindow* window, int width, int height) 306 { 307 GlfwWindow wnd = cast(GlfwWindow)glfwGetWindowUserPointer(window); 308 wnd.glfwOnFramebufferSize(width,height); 309 } 310 311 void window_focus_callback(GLFWwindow* window, int gainedFocus) 312 { 313 GlfwWindow wnd = cast(GlfwWindow)glfwGetWindowUserPointer(window); 314 wnd.glfwOnWindowFocus(gainedFocus!=0); 315 } 316 }