1 
2 #ifdef B3_USE_GLFW
3 #include "GLFWOpenGLWindow.h"
4 
5 #include <glad/gl.h>
6 #include <GLFW/glfw3.h>
7 
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include "LinearMath/btScalar.h"
11 
12 struct GLFWOpenGLWindowInternalData
13 {
14 	bool m_requestedExit;
15 	bool m_hasCursorPos;
16 	bool m_altPressed;
17 	bool m_shiftPressed;
18 	bool m_ctrlPressed;
19 	float m_cursorXPos;
20 	float m_cursorYPos;
21 	b3MouseMoveCallback m_mouseMoveCallback;
22 	b3MouseButtonCallback m_mouseButtonCallback;
23 	b3ResizeCallback m_resizeCallback;
24 	b3WheelCallback m_wheelCallback;
25 	b3KeyboardCallback m_keyboardCallback;
26 	b3RenderCallback m_renderCallback;
27 	int m_width;
28 	int m_height;
29 	float m_retinaScaleFactor;
30 
31 	GLFWwindow* m_glfwWindow;
32 
GLFWOpenGLWindowInternalDataGLFWOpenGLWindowInternalData33 	GLFWOpenGLWindowInternalData()
34 		: m_requestedExit(false),
35 		  m_hasCursorPos(false),
36 		  m_altPressed(false),
37 		  m_shiftPressed(false),
38 		  m_ctrlPressed(false),
39 		  m_cursorXPos(0),
40 		  m_cursorYPos(0),
41 		  m_mouseMoveCallback(0),
42 		  m_mouseButtonCallback(0),
43 		  m_resizeCallback(0),
44 		  m_wheelCallback(0),
45 		  m_keyboardCallback(0),
46 		  m_renderCallback(0),
47 		  m_width(0),
48 		  m_height(0),
49 		  m_retinaScaleFactor(1),
50 		  m_glfwWindow(0)
51 	{
52 	}
53 };
54 
GLFWErrorCallback(int error,const char * description)55 static void GLFWErrorCallback(int error, const char* description)
56 {
57 	fprintf(stderr, "Error: %s\n", description);
58 }
59 
GLFWMouseButtonCallback(GLFWwindow * window,int button,int glfwState,int)60 static void GLFWMouseButtonCallback(GLFWwindow* window, int button, int glfwState, int)
61 {
62 	GLFWOpenGLWindow* wnd = (GLFWOpenGLWindow*)glfwGetWindowUserPointer(window);
63 	if (wnd && wnd->getMouseButtonCallback())
64 	{
65 		int state = (glfwState == GLFW_PRESS) ? 1 : 0;
66 		wnd->mouseButtonCallbackInternal(button, state);
67 	}
68 }
69 
GLFWScrollCallback(GLFWwindow * window,double deltaX,double deltaY)70 static void GLFWScrollCallback(GLFWwindow* window, double deltaX, double deltaY)
71 {
72 	GLFWOpenGLWindow* wnd = (GLFWOpenGLWindow*)glfwGetWindowUserPointer(window);
73 	if (wnd && wnd->getWheelCallback())
74 	{
75 		wnd->getWheelCallback()(deltaX * 100, deltaY * 100);
76 	}
77 }
78 
GLFWCursorPosCallback(GLFWwindow * window,double xPos,double yPos)79 static void GLFWCursorPosCallback(GLFWwindow* window, double xPos, double yPos)
80 {
81 	GLFWOpenGLWindow* wnd = (GLFWOpenGLWindow*)glfwGetWindowUserPointer(window);
82 	if (wnd && wnd->getMouseMoveCallback())
83 	{
84 		wnd->mouseCursorCallbackInternal(xPos, yPos);
85 	}
86 }
87 
GLFWKeyCallback(GLFWwindow * window,int key,int scancode,int action,int mods)88 static void GLFWKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
89 {
90 	GLFWOpenGLWindow* wnd = (GLFWOpenGLWindow*)glfwGetWindowUserPointer(window);
91 	if (wnd)
92 	{
93 		wnd->keyboardCallbackInternal(key, action);
94 	}
95 	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
96 	{
97 		glfwSetWindowShouldClose(window, GLFW_TRUE);
98 	}
99 }
100 
GLFWSizeCallback(GLFWwindow * window,int width,int height)101 static void GLFWSizeCallback(GLFWwindow* window, int width, int height)
102 {
103 	GLFWOpenGLWindow* wnd = (GLFWOpenGLWindow*)glfwGetWindowUserPointer(window);
104 	{
105 		wnd->resizeInternal(width, height);
106 	}
107 }
108 
GLFWOpenGLWindow()109 GLFWOpenGLWindow::GLFWOpenGLWindow()
110 {
111 	m_data = new GLFWOpenGLWindowInternalData();
112 }
113 
~GLFWOpenGLWindow()114 GLFWOpenGLWindow::~GLFWOpenGLWindow()
115 {
116 	if (m_data->m_glfwWindow)
117 	{
118 		closeWindow();
119 	}
120 	delete m_data;
121 }
122 
getBulletKeyFromGLFWKeycode(int glfwKeyCode)123 int getBulletKeyFromGLFWKeycode(int glfwKeyCode)
124 {
125 	int keycode = -1;
126 	if (glfwKeyCode >= 'A' && glfwKeyCode <= 'Z')
127 	{
128 		return glfwKeyCode + 32;  //todo: fix the ascii A vs a input
129 	}
130 	if (glfwKeyCode >= '0' && glfwKeyCode <= '9')
131 	{
132 		return glfwKeyCode;
133 	}
134 
135 	switch (glfwKeyCode)
136 	{
137 		case GLFW_KEY_ENTER:
138 		{
139 			keycode = B3G_RETURN;
140 			break;
141 		};
142 		case GLFW_KEY_ESCAPE:
143 		{
144 			keycode = B3G_ESCAPE;
145 			break;
146 		};
147 		case GLFW_KEY_F1:
148 		{
149 			keycode = B3G_F1;
150 			break;
151 		}
152 		case GLFW_KEY_F2:
153 		{
154 			keycode = B3G_F2;
155 			break;
156 		}
157 		case GLFW_KEY_F3:
158 		{
159 			keycode = B3G_F3;
160 			break;
161 		}
162 		case GLFW_KEY_F4:
163 		{
164 			keycode = B3G_F4;
165 			break;
166 		}
167 		case GLFW_KEY_F5:
168 		{
169 			keycode = B3G_F5;
170 			break;
171 		}
172 		case GLFW_KEY_F6:
173 		{
174 			keycode = B3G_F6;
175 			break;
176 		}
177 		case GLFW_KEY_F7:
178 		{
179 			keycode = B3G_F7;
180 			break;
181 		}
182 		case GLFW_KEY_F8:
183 		{
184 			keycode = B3G_F8;
185 			break;
186 		}
187 		case GLFW_KEY_F9:
188 		{
189 			keycode = B3G_F9;
190 			break;
191 		}
192 		case GLFW_KEY_F10:
193 		{
194 			keycode = B3G_F10;
195 			break;
196 		}
197 
198 			//case GLFW_KEY_SPACE: {keycode= ' '; break;}
199 
200 		case GLFW_KEY_PAGE_DOWN:
201 		{
202 			keycode = B3G_PAGE_DOWN;
203 			break;
204 		}
205 		case GLFW_KEY_PAGE_UP:
206 		{
207 			keycode = B3G_PAGE_UP;
208 			break;
209 		}
210 
211 		case GLFW_KEY_INSERT:
212 		{
213 			keycode = B3G_INSERT;
214 			break;
215 		}
216 		case GLFW_KEY_BACKSPACE:
217 		{
218 			keycode = B3G_BACKSPACE;
219 			break;
220 		}
221 		case GLFW_KEY_DELETE:
222 		{
223 			keycode = B3G_DELETE;
224 			break;
225 		}
226 
227 		case GLFW_KEY_END:
228 		{
229 			keycode = B3G_END;
230 			break;
231 		}
232 		case GLFW_KEY_HOME:
233 		{
234 			keycode = B3G_HOME;
235 			break;
236 		}
237 		case GLFW_KEY_LEFT:
238 		{
239 			keycode = B3G_LEFT_ARROW;
240 			break;
241 		}
242 		case GLFW_KEY_UP:
243 		{
244 			keycode = B3G_UP_ARROW;
245 			break;
246 		}
247 		case GLFW_KEY_RIGHT:
248 		{
249 			keycode = B3G_RIGHT_ARROW;
250 			break;
251 		}
252 		case GLFW_KEY_DOWN:
253 		{
254 			keycode = B3G_DOWN_ARROW;
255 			break;
256 		}
257 		case GLFW_KEY_RIGHT_SHIFT:
258 		{
259 			keycode = B3G_SHIFT;
260 			break;
261 		}
262 		case GLFW_KEY_LEFT_SHIFT:
263 		{
264 			keycode = B3G_SHIFT;
265 			break;
266 		}
267 		case GLFW_KEY_MENU:
268 		{
269 			keycode = B3G_ALT;
270 			break;
271 		}
272 		case GLFW_KEY_RIGHT_CONTROL:
273 		{
274 			keycode = B3G_CONTROL;
275 			break;
276 		}
277 		case GLFW_KEY_LEFT_CONTROL:
278 		{
279 			keycode = B3G_CONTROL;
280 			break;
281 		}
282 		default:
283 		{
284 			//keycode = MapVirtualKey( virtualKeyCode, MAPGLFW_KEY_GLFW_KEY_TO_CHAR ) & 0x0000FFFF;
285 		}
286 	};
287 
288 	return keycode;
289 }
290 
keyboardCallbackInternal(int key,int state)291 void GLFWOpenGLWindow::keyboardCallbackInternal(int key, int state)
292 {
293 	if (getKeyboardCallback())
294 	{
295 		//convert keyboard codes from glfw to bullet
296 		int btcode = getBulletKeyFromGLFWKeycode(key);
297 		int btstate = (state == GLFW_RELEASE) ? 0 : 1;
298 
299 		switch (btcode)
300 		{
301 			case B3G_SHIFT:
302 			{
303 				m_data->m_shiftPressed = state != 0;
304 				break;
305 			}
306 			case B3G_ALT:
307 			{
308 				m_data->m_altPressed = state != 0;
309 				break;
310 			}
311 			case B3G_CONTROL:
312 			{
313 				m_data->m_ctrlPressed = state != 0;
314 				break;
315 			}
316 			default:
317 			{
318 			}
319 		}
320 
321 		getKeyboardCallback()(btcode, btstate);
322 	}
323 }
324 
mouseButtonCallbackInternal(int button,int state)325 void GLFWOpenGLWindow::mouseButtonCallbackInternal(int button, int state)
326 {
327 	if (getMouseButtonCallback() && m_data->m_hasCursorPos)
328 	{
329 		getMouseButtonCallback()(button, state, m_data->m_cursorXPos, m_data->m_cursorYPos);
330 	}
331 }
332 
mouseCursorCallbackInternal(double xPos,double yPos)333 void GLFWOpenGLWindow::mouseCursorCallbackInternal(double xPos, double yPos)
334 {
335 	if (getMouseMoveCallback())
336 	{
337 		m_data->m_hasCursorPos = true;
338 		m_data->m_cursorXPos = xPos;
339 		m_data->m_cursorYPos = yPos;
340 		getMouseMoveCallback()(xPos, yPos);
341 	}
342 }
343 
resizeInternal(int width,int height)344 void GLFWOpenGLWindow::resizeInternal(int width, int height)
345 {
346 	glfwGetFramebufferSize(m_data->m_glfwWindow, &m_data->m_width, &m_data->m_height);
347 	glViewport(0, 0, m_data->m_width, m_data->m_height);
348 
349 	if (getResizeCallback())
350 	{
351 		getResizeCallback()(m_data->m_width / m_data->m_retinaScaleFactor, m_data->m_height / m_data->m_retinaScaleFactor);
352 	}
353 }
354 
createDefaultWindow(int width,int height,const char * title)355 void GLFWOpenGLWindow::createDefaultWindow(int width, int height, const char* title)
356 {
357 	b3gWindowConstructionInfo ci;
358 	ci.m_width = width;
359 	ci.m_height = height;
360 	ci.m_title = title;
361 
362 	createWindow(ci);
363 }
364 
createWindow(const b3gWindowConstructionInfo & ci)365 void GLFWOpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci)
366 {
367 	btAssert(m_data->m_glfwWindow == 0);
368 	if (m_data->m_glfwWindow == 0)
369 	{
370 		glfwSetErrorCallback(GLFWErrorCallback);
371 
372 		if (!glfwInit())
373 			exit(EXIT_FAILURE);
374 
375 		if (ci.m_openglVersion == 2)
376 		{
377 			glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
378 			glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
379 		}
380 		else
381 		{
382 			glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
383 			glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
384 			glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
385 			glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
386 		}
387 
388 		m_data->m_glfwWindow = glfwCreateWindow(ci.m_width, ci.m_height, ci.m_title, NULL, NULL);
389 
390 		if (!m_data->m_glfwWindow)
391 		{
392 			glfwTerminate();
393 			exit(EXIT_FAILURE);
394 		}
395 
396 		glfwSetKeyCallback(m_data->m_glfwWindow, GLFWKeyCallback);
397 		glfwSetMouseButtonCallback(m_data->m_glfwWindow, GLFWMouseButtonCallback);
398 
399 		glfwSetCursorPosCallback(m_data->m_glfwWindow, GLFWCursorPosCallback);
400 		glfwSetScrollCallback(m_data->m_glfwWindow, GLFWScrollCallback);
401 
402 		glfwSetWindowSizeCallback(m_data->m_glfwWindow, GLFWSizeCallback);
403 		glfwSetWindowUserPointer(m_data->m_glfwWindow, this);
404 
405 		glfwMakeContextCurrent(m_data->m_glfwWindow);
406 		gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
407 		glfwSwapInterval(0);  //1);
408 		glfwGetFramebufferSize(m_data->m_glfwWindow, &m_data->m_width, &m_data->m_height);
409 		int windowWidth, windowHeight;
410 		glfwGetWindowSize(m_data->m_glfwWindow, &windowWidth, &windowHeight);
411 		m_data->m_retinaScaleFactor = float(m_data->m_width) / float(windowWidth);
412 		glViewport(0, 0, m_data->m_width, m_data->m_height);
413 	}
414 }
415 
closeWindow()416 void GLFWOpenGLWindow::closeWindow()
417 {
418 	if (m_data->m_glfwWindow)
419 	{
420 		glfwDestroyWindow(m_data->m_glfwWindow);
421 
422 		glfwTerminate();
423 		m_data->m_glfwWindow = 0;
424 	}
425 }
426 
runMainLoop()427 void GLFWOpenGLWindow::runMainLoop()
428 {
429 }
430 
getTimeInSeconds()431 float GLFWOpenGLWindow::getTimeInSeconds()
432 {
433 	return 0.f;
434 }
435 
requestedExit() const436 bool GLFWOpenGLWindow::requestedExit() const
437 {
438 	bool shouldClose = m_data->m_requestedExit;
439 
440 	if (m_data->m_glfwWindow)
441 	{
442 		shouldClose = shouldClose || glfwWindowShouldClose(m_data->m_glfwWindow);
443 	}
444 	return shouldClose;
445 }
446 
setRequestExit()447 void GLFWOpenGLWindow::setRequestExit()
448 {
449 	if (m_data->m_glfwWindow)
450 	{
451 		glfwSetWindowShouldClose(m_data->m_glfwWindow, GLFW_TRUE);
452 	}
453 	m_data->m_requestedExit = true;
454 }
455 
startRendering()456 void GLFWOpenGLWindow::startRendering()
457 {
458 	if (m_data->m_glfwWindow)
459 	{
460 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
461 	}
462 }
463 
endRendering()464 void GLFWOpenGLWindow::endRendering()
465 {
466 	glfwPollEvents();
467 	glfwSwapBuffers(m_data->m_glfwWindow);
468 }
469 
isModifierKeyPressed(int key)470 bool GLFWOpenGLWindow::isModifierKeyPressed(int key)
471 {
472 	bool result = false;
473 
474 	switch (key)
475 	{
476 		case B3G_SHIFT:
477 		{
478 			result = m_data->m_shiftPressed;
479 			break;
480 		}
481 		case B3G_ALT:
482 		{
483 			result = m_data->m_altPressed;
484 			break;
485 		}
486 		case B3G_CONTROL:
487 		{
488 			result = m_data->m_ctrlPressed;
489 			break;
490 		}
491 		default:
492 		{
493 		}
494 	}
495 	return result;
496 }
497 
setMouseMoveCallback(b3MouseMoveCallback mouseCallback)498 void GLFWOpenGLWindow::setMouseMoveCallback(b3MouseMoveCallback mouseCallback)
499 {
500 	m_data->m_mouseMoveCallback = mouseCallback;
501 }
502 
getMouseMoveCallback()503 b3MouseMoveCallback GLFWOpenGLWindow::getMouseMoveCallback()
504 {
505 	return m_data->m_mouseMoveCallback;
506 }
507 
setMouseButtonCallback(b3MouseButtonCallback mouseCallback)508 void GLFWOpenGLWindow::setMouseButtonCallback(b3MouseButtonCallback mouseCallback)
509 {
510 	m_data->m_mouseButtonCallback = mouseCallback;
511 }
512 
getMouseButtonCallback()513 b3MouseButtonCallback GLFWOpenGLWindow::getMouseButtonCallback()
514 {
515 	return m_data->m_mouseButtonCallback;
516 }
517 
setResizeCallback(b3ResizeCallback resizeCallback)518 void GLFWOpenGLWindow::setResizeCallback(b3ResizeCallback resizeCallback)
519 {
520 	m_data->m_resizeCallback = resizeCallback;
521 	getResizeCallback()(m_data->m_width / getRetinaScale(), m_data->m_height / getRetinaScale());
522 }
523 
getResizeCallback()524 b3ResizeCallback GLFWOpenGLWindow::getResizeCallback()
525 {
526 	return m_data->m_resizeCallback;
527 }
528 
setWheelCallback(b3WheelCallback wheelCallback)529 void GLFWOpenGLWindow::setWheelCallback(b3WheelCallback wheelCallback)
530 {
531 	m_data->m_wheelCallback = wheelCallback;
532 }
533 
getWheelCallback()534 b3WheelCallback GLFWOpenGLWindow::getWheelCallback()
535 {
536 	return m_data->m_wheelCallback;
537 }
538 
setKeyboardCallback(b3KeyboardCallback keyboardCallback)539 void GLFWOpenGLWindow::setKeyboardCallback(b3KeyboardCallback keyboardCallback)
540 {
541 	m_data->m_keyboardCallback = keyboardCallback;
542 }
543 
getKeyboardCallback()544 b3KeyboardCallback GLFWOpenGLWindow::getKeyboardCallback()
545 {
546 	return m_data->m_keyboardCallback;
547 }
548 
setRenderCallback(b3RenderCallback renderCallback)549 void GLFWOpenGLWindow::setRenderCallback(b3RenderCallback renderCallback)
550 {
551 	m_data->m_renderCallback = renderCallback;
552 }
553 
setWindowTitle(const char * title)554 void GLFWOpenGLWindow::setWindowTitle(const char* title)
555 {
556 	if (m_data->m_glfwWindow)
557 	{
558 		glfwSetWindowTitle(m_data->m_glfwWindow, title);
559 	}
560 }
561 
getRetinaScale() const562 float GLFWOpenGLWindow::getRetinaScale() const
563 {
564 	return m_data->m_retinaScaleFactor;
565 }
setAllowRetina(bool allow)566 void GLFWOpenGLWindow::setAllowRetina(bool allow)
567 {
568 }
569 
getWidth() const570 int GLFWOpenGLWindow::getWidth() const
571 {
572 	if (m_data->m_glfwWindow)
573 	{
574 		glfwGetFramebufferSize(m_data->m_glfwWindow, &m_data->m_width, &m_data->m_height);
575 	}
576 	int width = m_data->m_width / m_data->m_retinaScaleFactor;
577 	return width;
578 }
getHeight() const579 int GLFWOpenGLWindow::getHeight() const
580 {
581 	if (m_data->m_glfwWindow)
582 	{
583 		glfwGetFramebufferSize(m_data->m_glfwWindow, &m_data->m_width, &m_data->m_height);
584 	}
585 	return m_data->m_height / m_data->m_retinaScaleFactor;
586 }
587 
fileOpenDialog(char * fileName,int maxFileNameLength)588 int GLFWOpenGLWindow::fileOpenDialog(char* fileName, int maxFileNameLength)
589 {
590 	return 0;
591 }
592 
593 #endif  //B3_USE_GLFW
594