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