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 }