1 /** 2 Copyright: Copyright (c) 2013-2016 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module anchovy.glfwwindow; 8 9 import std.conv : to; 10 import std.string : toStringz, fromStringz, format; 11 12 import derelict.glfw3.glfw3; 13 import derelict.opengl3.gl3; 14 import voxelman.math; 15 import anchovy.iwindow : IWindow; 16 17 class GlfwWindow : IWindow 18 { 19 private: 20 GLFWwindow* glfwWindowPtr; 21 static bool glfwInited = false; 22 bool isProcessingEvents = false; 23 24 public: 25 override void init(uvec2 size, in string caption) 26 { 27 if (!glfwInited) 28 initGlfw(); 29 30 scope(failure) glfwTerminate(); 31 32 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 33 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); 34 //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 35 36 //BUG: sometimes fails in Windows 8. Maybe because of old drivers. 37 glfwWindowPtr = glfwCreateWindow(size.x, size.y, toStringz(caption), null, null); 38 39 if (glfwWindowPtr is null) 40 { 41 throw new Error("Error creating GLFW3 window"); 42 } 43 44 glfwMakeContextCurrent(glfwWindowPtr); 45 glfwSwapInterval(0); 46 47 glClearColor(1.0, 1.0, 1.0, 1.0); 48 glViewport(0, 0, size.x, size.y); 49 50 DerelictGL3.reload(); 51 52 glfwSetWindowUserPointer(glfwWindowPtr, cast(void*)this); 53 glfwSetWindowPosCallback(glfwWindowPtr, &windowposfun); 54 glfwSetFramebufferSizeCallback(glfwWindowPtr, &windowsizefun); 55 glfwSetWindowCloseCallback(glfwWindowPtr, &windowclosefun); 56 //glfwSetWindowRefreshCallback(glfwWindowPtr, &windowrefreshfun); 57 glfwSetWindowFocusCallback(glfwWindowPtr, &windowfocusfun); 58 glfwSetWindowIconifyCallback(glfwWindowPtr, &windowiconifyfun); 59 glfwSetMouseButtonCallback(glfwWindowPtr, &mousebuttonfun); 60 glfwSetCursorPosCallback(glfwWindowPtr, &cursorposfun); 61 glfwSetScrollCallback(glfwWindowPtr, &scrollfun); 62 glfwSetKeyCallback(glfwWindowPtr, &keyfun); 63 glfwSetCharCallback(glfwWindowPtr, &charfun); 64 //glfwSetCursorEnterCallback(window, GLFWcursorenterfun cbfun); 65 glfwSetWindowRefreshCallback(glfwWindowPtr, &refreshfun); 66 } 67 68 override void processEvents() 69 { 70 // prevent calling glfwPollEvents when inside window_refresh callback 71 if (!isProcessingEvents) 72 { 73 isProcessingEvents = true; 74 glfwPollEvents(); 75 isProcessingEvents = false; 76 } 77 } 78 79 override double elapsedTime() @property //in seconds 80 { 81 return glfwGetTime(); 82 } 83 84 override void reshape(uvec2 viewportSize) 85 { 86 glViewport(0, 0, cast(int)viewportSize.x, cast(int)viewportSize.y); 87 } 88 89 override void releaseWindow() 90 { 91 glfwDestroyWindow(glfwWindowPtr); 92 glfwTerminate(); 93 } 94 95 override void mousePosition(ivec2 newPosition) @property 96 { 97 glfwSetCursorPos(glfwWindowPtr, newPosition.x, newPosition.y); 98 } 99 100 override ivec2 mousePosition() @property 101 { 102 double x, y; 103 glfwGetCursorPos(glfwWindowPtr, &x, &y); 104 return ivec2(cast(int)x, cast(int)y); 105 } 106 107 override void swapBuffers() 108 { 109 glfwSwapBuffers(glfwWindowPtr); 110 } 111 112 override void size(uvec2 newSize) @property 113 { 114 glfwSetWindowSize(glfwWindowPtr, cast(int)newSize.x, cast(int)newSize.y); 115 } 116 117 override uvec2 size() @property 118 { 119 int width, height; 120 glfwGetWindowSize(glfwWindowPtr, &width, &height); 121 return uvec2(cast(uint)width, cast(uint)height); 122 } 123 124 override uvec2 framebufferSize() @property 125 { 126 int width, height; 127 glfwGetFramebufferSize(glfwWindowPtr, &width, &height); 128 return uvec2(cast(uint)width, cast(uint)height); 129 } 130 131 override string clipboardString() @property 132 { 133 const(char*) data = glfwGetClipboardString(glfwWindowPtr); 134 if (data is null) return ""; 135 return cast(string)fromStringz(data); 136 } 137 138 override void clipboardString(string newClipboardString) @property 139 { 140 glfwSetClipboardString(glfwWindowPtr, toStringz(newClipboardString)); 141 } 142 143 override bool isKeyPressed(uint key) 144 { 145 return glfwGetKey(glfwWindowPtr, key) == GLFW_PRESS; 146 } 147 148 GLFWwindow* handle() @property 149 { 150 return glfwWindowPtr; 151 } 152 153 private: 154 static void initGlfw() 155 { 156 glfwSetErrorCallback(&errorfun); 157 158 if (glfwInit() == 0) 159 { 160 throw new Error("Error initializing GLFW3"); //TODO: add proper error handling 161 } 162 glfwInited = true; 163 } 164 } 165 166 GlfwWindow getWinFromUP(GLFWwindow* w) nothrow 167 { 168 GlfwWindow win; 169 win = cast(GlfwWindow) glfwGetWindowUserPointer(w); 170 return win; 171 } 172 173 extern(C) nothrow 174 { 175 void errorfun(int errorCode, const(char)* msg) 176 { 177 throw new Error(format("GLFW error [%s] : %s", errorCode, fromStringz(msg))); 178 } 179 void windowposfun(GLFWwindow* w, int nx, int ny) 180 { 181 try getWinFromUP(w).windowMoved.emit(ivec2(nx, ny)); 182 catch(Exception e) throw new Error(to!string(e)); 183 } 184 void windowsizefun(GLFWwindow* w, int newWidth, int newHeight) 185 { 186 try getWinFromUP(w).windowResized.emit(uvec2(cast(uint)newWidth, cast(uint)newHeight)); 187 catch(Exception e) throw new Error(to!string(e)); 188 } 189 void windowclosefun(GLFWwindow* w) 190 { 191 try getWinFromUP(w).closePressed.emit(); 192 catch(Exception e) throw new Error(to!string(e)); 193 } 194 void windowrefreshfun(GLFWwindow* w) 195 { 196 197 } 198 void windowfocusfun(GLFWwindow* w, int focus) 199 { 200 try getWinFromUP(w).focusChanged.emit(cast(bool)focus); 201 catch(Exception e) throw new Error(to!string(e)); 202 } 203 void windowiconifyfun(GLFWwindow* w, int iconified) 204 { 205 try getWinFromUP(w).windowIconified.emit(cast(bool)iconified); 206 catch(Exception e) throw new Error(to!string(e)); 207 } 208 void mousebuttonfun(GLFWwindow* w, int mouseButton, int action, int) 209 { 210 try 211 { 212 if(action == GLFW_RELEASE) 213 { 214 getWinFromUP(w).mouseReleased.emit(mouseButton); 215 } 216 else 217 { 218 getWinFromUP(w).mousePressed.emit(mouseButton); 219 } 220 } 221 catch(Exception e) throw new Error(to!string(e)); 222 } 223 void cursorposfun(GLFWwindow* w, double nx, double ny) 224 { 225 try getWinFromUP(w).mouseMoved.emit(ivec2(cast(int)nx, cast(int)ny)); 226 catch(Exception e) throw new Error(to!string(e)); 227 } 228 void scrollfun(GLFWwindow* w, double x, double y) 229 { 230 try getWinFromUP(w).wheelScrolled.emit(dvec2(x, y)); 231 catch(Exception e) throw new Error(to!string(e)); 232 } 233 void cursorenterfun(GLFWwindow* w, int) 234 { 235 236 } 237 void keyfun(GLFWwindow* w, int key, int, int action, int) 238 { 239 if (key < 0) return; 240 try 241 { 242 if (action == GLFW_RELEASE) 243 { 244 getWinFromUP(w).keyReleased.emit(key); 245 } 246 else 247 { 248 getWinFromUP(w).keyPressed.emit(key); 249 } 250 } 251 catch(Exception e) throw new Error(to!string(e)); 252 } 253 void charfun(GLFWwindow* w, uint unicode) 254 { 255 if (unicode > 0 && unicode < 0x10000) { 256 try getWinFromUP(w).charEntered.emit(cast(dchar)unicode); 257 catch(Exception e) throw new Error(to!string(e)); 258 } 259 } 260 void refreshfun(GLFWwindow* w) 261 { 262 try getWinFromUP(w).refresh.emit(); 263 catch(Exception e) throw new Error(to!string(e)); 264 } 265 }