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 		DerelictGLFW3.load();
170 		DerelictGL3.load();
171 
172 		glfwSetErrorCallback(&errorfun);
173 
174 		if (glfwInit() == 0)
175 		{
176 			throw new Error("Error initializing GLFW3"); //TODO: add proper error handling
177 		}
178 
179 		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
180 		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
181 		//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
182 
183 		glfwInited = true;
184 	}
185 
186 private:
187 
188 
189 	GLFWwindow*	_window;
190 	uvec2 _size;
191 
192 	bool _mouseGrabbed = false;
193 
194 	static bool	glfwInited = false;
195 }
196 
197 static GlfwWindow getWinFromUP(GLFWwindow* w) nothrow
198 {
199 	GlfwWindow win;
200 	win = cast(GlfwWindow) glfwGetWindowUserPointer(w);
201 	return win;
202 }
203 
204 extern(C)
205 {
206 	static void errorfun(int errorCode, const(char)* msg) nothrow
207 	{
208 		throw new Error("GLFW error ocured ["~to!string(errorCode)~"] : "~ZToString(msg));
209 	}
210 	static void windowposfun(GLFWwindow* w, int nx, int ny) nothrow
211 	{
212 		try
213 		{
214 			getWinFromUP(w).windowMoved.emit(ivec2(nx, ny));
215 		}
216 		catch(Exception e)
217 		{
218 			throw new Error(to!string(e));
219 		}
220 	}
221 	static void windowsizefun(GLFWwindow* w, int newWidth, int newHeight) nothrow
222 	{
223 		try
224 		{
225 			getWinFromUP(w).windowResized.emit(uvec2(cast(uint)newWidth, cast(uint)newHeight));
226 		}
227 		catch(Exception e)
228 		{
229 			throw new Error(to!string(e));
230 		}
231 	}
232 	static void windowclosefun(GLFWwindow* w) nothrow
233 	{
234 		try
235 		{
236 			getWinFromUP(w).closePressed.emit();//------------------
237 		}
238 		catch(Exception e)
239 		{
240 			throw new Error(to!string(e));
241 		}
242 	}
243 	static void windowrefreshfun(GLFWwindow* w) nothrow
244 	{
245 
246 	}
247 	static void windowfocusfun(GLFWwindow* w, int focus) nothrow
248 	{
249 		try
250 		{
251 			getWinFromUP(w).focusChanged.emit(cast(bool)focus);
252 		}
253 		catch(Exception e)
254 		{
255 			throw new Error(to!string(e));
256 		}
257 	}
258 	static void windowiconifyfun(GLFWwindow* w, int iconified) nothrow
259 	{
260 		try
261 		{
262 			getWinFromUP(w).windowIconified.emit(cast(bool)iconified);
263 		}
264 		catch(Exception e)
265 		{
266 			throw new Error(to!string(e));
267 		}
268 	}
269 	static void mousebuttonfun(GLFWwindow* w, int mouseButton, int action, int) nothrow
270 	{
271 		try
272 		{
273 			if(action == GLFW_RELEASE)
274 			{
275 				getWinFromUP(w).mouseReleased.emit(mouseButton);
276 			}
277 			else
278 			{
279 				getWinFromUP(w).mousePressed.emit(mouseButton);
280 			}
281 		}
282 		catch(Exception e)
283 		{
284 			throw new Error(to!string(e));
285 		}
286 	}
287 	static void cursorposfun(GLFWwindow* w, double nx, double ny) nothrow
288 	{
289 		try
290 		{
291 			getWinFromUP(w).mouseMoved.emit(ivec2(cast(int)nx, cast(int)ny));
292 		}
293 		catch(Exception e)
294 		{
295 			throw new Error(to!string(e));
296 		}
297 	}
298 	static void scrollfun(GLFWwindow* w, double x, double y) nothrow
299 	{
300 		try
301 		{
302 			getWinFromUP(w).wheelScrolled.emit(dvec2(x, y));
303 		}
304 		catch(Exception e)
305 		{
306 			throw new Error(to!string(e));
307 		}
308 	}
309 	static void cursorenterfun(GLFWwindow* w, int) nothrow
310 	{
311 
312 	}
313 	static void keyfun(GLFWwindow* w, int key, int, int action, int) nothrow
314 	{
315 		try
316 		{
317 			if (action == GLFW_RELEASE)
318 			{
319 				getWinFromUP(w).keyReleased.emit(key);
320 			}
321 			else
322 			{
323 				getWinFromUP(w).keyPressed.emit(key);
324 			}
325 		}
326 		catch(Exception e)
327 		{
328 			throw new Error(to!string(e));
329 		}
330 	}
331 	static void charfun(GLFWwindow* w, uint unicode) nothrow
332 	{
333 		try
334 		{
335 			getWinFromUP(w).charEntered.emit(cast(dchar)unicode);
336 		}
337 		catch(Exception e)
338 		{
339 			throw new Error(to!string(e));
340 		}
341 	}
342 }