1 /* 2 Copyright (c) 2013 Andrey Penechko 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license the "Software" to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 29 module anchovy.graphics.windows.glfwwindow; 30 31 private 32 { 33 import std.conv : to; 34 import std.stdio; 35 import std..string; 36 import anchovy.core.interfaces.iwindow; 37 } 38 39 public 40 { 41 import derelict.glfw3.glfw3; 42 import derelict.opengl3.gl3; 43 import anchovy.utils..string; 44 } 45 46 class GlfwWindow : IWindow 47 { 48 public: 49 50 override void init(uvec2 size, in string caption) 51 { 52 if (!glfwInited) 53 { 54 initGlfw(); 55 } 56 57 scope(failure) glfwTerminate(); 58 59 _size = size; 60 61 //BUG: sometimes fails in Windows 8. Maybe because of old drivers. 62 _window = glfwCreateWindow(_size.x, _size.y, toStringz(caption), null, null); 63 64 if (_window is null) 65 { 66 throw new Error("Error creating GLFW3 window"); 67 } 68 69 glfwMakeContextCurrent(_window); 70 glfwSwapInterval(0); 71 72 glClearColor(1.0, 1.0, 1.0, 1.0); 73 glViewport(0, 0, _size.x, _size.y); 74 75 DerelictGL3.reload(); 76 77 glfwSetWindowUserPointer(_window, cast(void*)this); 78 glfwSetWindowPosCallback(_window, &windowposfun); 79 glfwSetFramebufferSizeCallback(_window, &windowsizefun); 80 glfwSetWindowCloseCallback(_window, &windowclosefun); 81 //glfwSetWindowRefreshCallback(_window, &windowrefreshfun); 82 glfwSetWindowFocusCallback(_window, &windowfocusfun); 83 glfwSetWindowIconifyCallback(_window, &windowiconifyfun); 84 glfwSetMouseButtonCallback(_window, &mousebuttonfun); 85 glfwSetCursorPosCallback(_window, &cursorposfun); 86 glfwSetScrollCallback(_window, &scrollfun); 87 glfwSetKeyCallback(_window, &keyfun); 88 glfwSetCharCallback(_window, &charfun); 89 90 91 //glfwSetCursorEnterCallback(window, GLFWcursorenterfun cbfun); 92 } 93 94 override void processEvents() 95 { 96 glfwPollEvents(); 97 } 98 99 override double elapsedTime() @property //in seconds 100 { 101 return glfwGetTime(); 102 } 103 104 override void reshape(uvec2 viewportSize) 105 { 106 glViewport(0, 0, cast(int)viewportSize.x, cast(int)viewportSize.y); 107 } 108 109 override void releaseWindow() 110 { 111 glfwDestroyWindow(_window); 112 glfwTerminate(); 113 } 114 115 override void mousePosition(ivec2 newPosition) @property 116 { 117 glfwSetCursorPos(_window, newPosition.x, newPosition.y); 118 } 119 120 override ivec2 mousePosition() @property 121 { 122 double x, y; 123 glfwGetCursorPos(_window, &x, &y); 124 return ivec2(cast(int)x, cast(int)y); 125 } 126 127 override void swapBuffers() 128 { 129 glfwSwapBuffers(_window); 130 } 131 132 override void grabMouse(){} 133 134 override void releaseMouse(){} 135 136 override void size(uvec2 newSize) @property 137 { 138 glfwSetWindowSize(_window, cast(int)newSize.x, cast(int)newSize.y); 139 } 140 141 override uvec2 size() @property 142 { 143 int width, height; 144 glfwGetWindowSize(_window, &width, &height); 145 return uvec2(cast(uint)width, cast(uint)height); 146 } 147 148 override string clipboardString() @property 149 { 150 const(char*) data = glfwGetClipboardString(_window); 151 if (data is null) return ""; 152 return ZToString(data); 153 } 154 155 override void clipboardString(string newClipboardString) @property 156 { 157 glfwSetClipboardString(_window, toStringz(newClipboardString)); 158 } 159 160 override bool isKeyPressed(uint key) 161 { 162 return glfwGetKey(_window, key) == GLFW_PRESS; 163 } 164 165 protected: 166 167 static void initGlfw() 168 { 169 glfwSetErrorCallback(&errorfun); 170 171 if (glfwInit() == 0) 172 { 173 throw new Error("Error initializing GLFW3"); //TODO: add proper error handling 174 } 175 176 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 177 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); 178 //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 179 180 glfwInited = true; 181 } 182 183 private: 184 185 186 GLFWwindow* _window; 187 uvec2 _size; 188 189 bool _mouseGrabbed = false; 190 191 static bool glfwInited = false; 192 } 193 194 static GlfwWindow getWinFromUP(GLFWwindow* w) nothrow 195 { 196 GlfwWindow win; 197 win = cast(GlfwWindow) glfwGetWindowUserPointer(w); 198 return win; 199 } 200 201 extern(C) 202 { 203 static void errorfun(int errorCode, const(char)* msg) nothrow 204 { 205 throw new Error("GLFW error ocured ["~to!string(errorCode)~"] : "~ZToString(msg)); 206 } 207 static void windowposfun(GLFWwindow* w, int nx, int ny) nothrow 208 { 209 try 210 { 211 getWinFromUP(w).windowMoved.emit(ivec2(nx, ny)); 212 } 213 catch(Exception e) 214 { 215 throw new Error(to!string(e)); 216 } 217 } 218 static void windowsizefun(GLFWwindow* w, int newWidth, int newHeight) nothrow 219 { 220 try 221 { 222 getWinFromUP(w).windowResized.emit(uvec2(cast(uint)newWidth, cast(uint)newHeight)); 223 } 224 catch(Exception e) 225 { 226 throw new Error(to!string(e)); 227 } 228 } 229 static void windowclosefun(GLFWwindow* w) nothrow 230 { 231 try 232 { 233 getWinFromUP(w).closePressed.emit();//------------------ 234 } 235 catch(Exception e) 236 { 237 throw new Error(to!string(e)); 238 } 239 } 240 static void windowrefreshfun(GLFWwindow* w) nothrow 241 { 242 243 } 244 static void windowfocusfun(GLFWwindow* w, int focus) nothrow 245 { 246 try 247 { 248 getWinFromUP(w).focusChanged.emit(cast(bool)focus); 249 } 250 catch(Exception e) 251 { 252 throw new Error(to!string(e)); 253 } 254 } 255 static void windowiconifyfun(GLFWwindow* w, int iconified) nothrow 256 { 257 try 258 { 259 getWinFromUP(w).windowIconified.emit(cast(bool)iconified); 260 } 261 catch(Exception e) 262 { 263 throw new Error(to!string(e)); 264 } 265 } 266 static void mousebuttonfun(GLFWwindow* w, int mouseButton, int action, int) nothrow 267 { 268 try 269 { 270 if(action == GLFW_RELEASE) 271 { 272 getWinFromUP(w).mouseReleased.emit(mouseButton); 273 } 274 else 275 { 276 getWinFromUP(w).mousePressed.emit(mouseButton); 277 } 278 } 279 catch(Exception e) 280 { 281 throw new Error(to!string(e)); 282 } 283 } 284 static void cursorposfun(GLFWwindow* w, double nx, double ny) nothrow 285 { 286 try 287 { 288 getWinFromUP(w).mouseMoved.emit(ivec2(cast(int)nx, cast(int)ny)); 289 } 290 catch(Exception e) 291 { 292 throw new Error(to!string(e)); 293 } 294 } 295 static void scrollfun(GLFWwindow* w, double x, double y) nothrow 296 { 297 try 298 { 299 getWinFromUP(w).wheelScrolled.emit(dvec2(x, y)); 300 } 301 catch(Exception e) 302 { 303 throw new Error(to!string(e)); 304 } 305 } 306 static void cursorenterfun(GLFWwindow* w, int) nothrow 307 { 308 309 } 310 static void keyfun(GLFWwindow* w, int key, int, int action, int) nothrow 311 { 312 try 313 { 314 if (action == GLFW_RELEASE) 315 { 316 getWinFromUP(w).keyReleased.emit(key); 317 } 318 else 319 { 320 getWinFromUP(w).keyPressed.emit(key); 321 } 322 } 323 catch(Exception e) 324 { 325 throw new Error(to!string(e)); 326 } 327 } 328 static void charfun(GLFWwindow* w, uint unicode) nothrow 329 { 330 try 331 { 332 getWinFromUP(w).charEntered.emit(cast(dchar)unicode); 333 } 334 catch(Exception e) 335 { 336 throw new Error(to!string(e)); 337 } 338 } 339 }