1 /*************************************************************************/
2 /*  os_bb10.cpp                                                          */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 #include "os_bb10.h"
31 
32 #include "core/os/dir_access.h"
33 #include "drivers/gles2/rasterizer_gles2.h"
34 #include "servers/visual/visual_server_raster.h"
35 
36 #include "bbutil.h"
37 #include "core/globals.h"
38 #include "core/os/keyboard.h"
39 #include "main/main.h"
40 #include <assert.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 
44 #include "bps/accelerometer.h"
45 #include "bps/audiodevice.h"
46 #include "bps/bps.h"
47 #include "bps/navigator.h"
48 #include "bps/orientation.h"
49 #include "bps/screen.h"
50 #include "bps/virtualkeyboard.h"
51 
52 #ifdef BB10_SCORELOOP_ENABLED
53 #include "modules/scoreloop/scoreloop_bb10.h"
54 #endif
55 
56 static char launch_dir[512];
57 char *launch_dir_ptr;
58 
get_video_driver_count() const59 int OSBB10::get_video_driver_count() const {
60 
61 	return 1;
62 }
get_video_driver_name(int p_driver) const63 const char *OSBB10::get_video_driver_name(int p_driver) const {
64 
65 	return "GLES2";
66 }
67 
get_default_video_mode() const68 OS::VideoMode OSBB10::get_default_video_mode() const {
69 
70 	return OS::VideoMode();
71 }
72 
get_audio_driver_count() const73 int OSBB10::get_audio_driver_count() const {
74 
75 	return 1;
76 }
get_audio_driver_name(int p_driver) const77 const char *OSBB10::get_audio_driver_name(int p_driver) const {
78 
79 	return "BB10";
80 }
81 
initialize(const VideoMode & p_desired,int p_video_driver,int p_audio_driver)82 void OSBB10::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
83 
84 	data_dir = getenv("HOME");
85 
86 	//Create a screen context that will be used to create an EGL surface to to receive libscreen events
87 	screen_create_context(&screen_cxt, 0);
88 
89 	//Initialize BPS library
90 	bps_initialize();
91 
92 	//Use utility code to initialize EGL for 2D rendering with GL ES 1.1
93 	enum RENDERING_API api = GL_ES_2;
94 #ifdef BB10_LGLES_OVERRIDE
95 	api = GL_ES_1;
96 #endif
97 	if (EXIT_SUCCESS != bbutil_init(screen_cxt, api)) {
98 		bbutil_terminate();
99 		screen_destroy_context(screen_cxt);
100 		return;
101 	};
102 
103 	EGLint surface_width, surface_height;
104 
105 	eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width);
106 	eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height);
107 	printf("screen size: %ix%i\n", surface_width, surface_height);
108 	VideoMode mode;
109 	mode.width = surface_width;
110 	mode.height = surface_height;
111 	mode.fullscreen = true;
112 	mode.resizable = false;
113 	set_video_mode(mode);
114 
115 	//Signal BPS library that navigator and screen events will be requested
116 	screen_request_events(screen_cxt);
117 	navigator_request_events(0);
118 	virtualkeyboard_request_events(0);
119 	audiodevice_request_events(0);
120 
121 #ifdef DEBUG_ENABLED
122 	bps_set_verbosity(3);
123 #endif
124 
125 	accel_supported = accelerometer_is_supported();
126 	if (accel_supported)
127 		accelerometer_set_update_frequency(FREQ_40_HZ);
128 	pitch = 0;
129 	roll = 0;
130 
131 #ifdef BB10_LGLES_OVERRIDE
132 	rasterizer = memnew(RasterizerGLES1(false));
133 #else
134 	rasterizer = memnew(RasterizerGLES2(false, false));
135 #endif
136 
137 	visual_server = memnew(VisualServerRaster(rasterizer));
138 	visual_server->init();
139 
140 	audio_driver = memnew(AudioDriverBB10);
141 	audio_driver->set_singleton();
142 	audio_driver->init(NULL);
143 
144 	sample_manager = memnew(SampleManagerMallocSW);
145 	audio_server = memnew(AudioServerSW(sample_manager));
146 	audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR, false);
147 	audio_server->init();
148 
149 	spatial_sound_server = memnew(SpatialSoundServerSW);
150 	spatial_sound_server->init();
151 
152 	spatial_sound_2d_server = memnew(SpatialSound2DServerSW);
153 	spatial_sound_2d_server->init();
154 
155 	//
156 	physics_server = memnew(PhysicsServerSW);
157 	physics_server->init();
158 	physics_2d_server = memnew(Physics2DServerSW);
159 	physics_2d_server->init();
160 
161 	input = memnew(InputDefault);
162 
163 #ifdef PAYMENT_SERVICE_ENABLED
164 	payment_service = memnew(PaymentService);
165 	Globals::get_singleton()->add_singleton(Globals::Singleton("InAppStore", payment_service));
166 #endif
167 }
168 
set_main_loop(MainLoop * p_main_loop)169 void OSBB10::set_main_loop(MainLoop *p_main_loop) {
170 
171 	input->set_main_loop(p_main_loop);
172 	main_loop = p_main_loop;
173 }
174 
delete_main_loop()175 void OSBB10::delete_main_loop() {
176 
177 	memdelete(main_loop);
178 	main_loop = NULL;
179 }
180 
finalize()181 void OSBB10::finalize() {
182 
183 	if (main_loop)
184 		memdelete(main_loop);
185 	main_loop = NULL;
186 
187 	spatial_sound_server->finish();
188 	memdelete(spatial_sound_server);
189 	spatial_sound_2d_server->finish();
190 	memdelete(spatial_sound_2d_server);
191 
192 	//if (debugger_connection_console) {
193 	//		memdelete(debugger_connection_console);
194 	//}
195 
196 	memdelete(sample_manager);
197 
198 	audio_server->finish();
199 	memdelete(audio_server);
200 
201 	visual_server->finish();
202 	memdelete(visual_server);
203 	memdelete(rasterizer);
204 
205 	physics_server->finish();
206 	memdelete(physics_server);
207 
208 	physics_2d_server->finish();
209 	memdelete(physics_2d_server);
210 
211 #ifdef PAYMENT_SERVICE_ENABLED
212 	memdelete(payment_service);
213 #endif
214 
215 	memdelete(input);
216 
217 	bbutil_terminate();
218 	screen_destroy_context(screen_cxt);
219 
220 	bps_shutdown();
221 }
222 
set_mouse_show(bool p_show)223 void OSBB10::set_mouse_show(bool p_show) {
224 
225 	//android has no mouse...
226 }
227 
set_mouse_grab(bool p_grab)228 void OSBB10::set_mouse_grab(bool p_grab) {
229 
230 	//it really has no mouse...!
231 }
232 
is_mouse_grab_enabled() const233 bool OSBB10::is_mouse_grab_enabled() const {
234 
235 	//*sigh* technology has evolved so much since i was a kid..
236 	return false;
237 }
get_mouse_pos() const238 Point2 OSBB10::get_mouse_pos() const {
239 
240 	return Point2();
241 }
get_mouse_button_state() const242 int OSBB10::get_mouse_button_state() const {
243 
244 	return 0;
245 }
set_window_title(const String & p_title)246 void OSBB10::set_window_title(const String &p_title) {
247 }
248 
249 //interesting byt not yet
250 //void set_clipboard(const String& p_text);
251 //String get_clipboard() const;
252 
set_video_mode(const VideoMode & p_video_mode,int p_screen)253 void OSBB10::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
254 
255 	default_videomode = p_video_mode;
256 }
257 
get_video_mode(int p_screen) const258 OS::VideoMode OSBB10::get_video_mode(int p_screen) const {
259 
260 	return default_videomode;
261 }
get_fullscreen_mode_list(List<VideoMode> * p_list,int p_screen) const262 void OSBB10::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
263 
264 	p_list->push_back(default_videomode);
265 }
266 
get_name()267 String OSBB10::get_name() {
268 
269 	return "BlackBerry 10";
270 }
271 
get_main_loop() const272 MainLoop *OSBB10::get_main_loop() const {
273 
274 	return main_loop;
275 }
276 
can_draw() const277 bool OSBB10::can_draw() const {
278 
279 	return !minimized;
280 }
281 
set_cursor_shape(CursorShape p_shape)282 void OSBB10::set_cursor_shape(CursorShape p_shape) {
283 
284 	//android really really really has no mouse.. how amazing..
285 }
286 
set_custom_mouse_cursor(const RES & p_cursor,CursorShape p_shape,const Vector2 & p_hotspot)287 void OSBB10::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
288 
289 	// Since BlackBerry 10 has no mouse, we do not need to change its texture (how amazing !)
290 }
291 
handle_screen_event(bps_event_t * event)292 void OSBB10::handle_screen_event(bps_event_t *event) {
293 
294 	screen_event_t screen_event = screen_event_get_event(event);
295 
296 	int screen_val;
297 	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &screen_val);
298 
299 	int pos[2];
300 
301 	switch (screen_val) {
302 		case SCREEN_EVENT_MTOUCH_TOUCH:
303 		case SCREEN_EVENT_MTOUCH_RELEASE: {
304 
305 			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_POSITION, pos);
306 
307 			InputEvent ievent;
308 			ievent.type = InputEvent::SCREEN_TOUCH;
309 			ievent.ID = ++last_id;
310 			ievent.device = 0;
311 			ievent.screen_touch.pressed = (screen_val == SCREEN_EVENT_MTOUCH_TOUCH);
312 			ievent.screen_touch.x = pos[0];
313 			ievent.screen_touch.y = pos[1];
314 			Point2 mpos(ievent.screen_touch.x, ievent.screen_touch.y);
315 
316 			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pos[0]);
317 			ievent.screen_touch.index = pos[0];
318 
319 			last_touch_x[pos[0]] = ievent.screen_touch.x;
320 			last_touch_y[pos[0]] = ievent.screen_touch.y;
321 
322 			input->parse_input_event(ievent);
323 
324 			if (ievent.screen_touch.index == 0) {
325 
326 				InputEvent ievent;
327 				ievent.type = InputEvent::MOUSE_BUTTON;
328 				ievent.ID = ++last_id;
329 				ievent.device = 0;
330 				ievent.mouse_button.pressed = (screen_val == SCREEN_EVENT_MTOUCH_TOUCH);
331 				ievent.mouse_button.button_index = BUTTON_LEFT;
332 				ievent.mouse_button.doubleclick = 0;
333 				ievent.mouse_button.x = ievent.mouse_button.global_x = mpos.x;
334 				ievent.mouse_button.y = ievent.mouse_button.global_y = mpos.y;
335 				input->parse_input_event(ievent);
336 			};
337 
338 		} break;
339 		case SCREEN_EVENT_MTOUCH_MOVE: {
340 
341 			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_POSITION, pos);
342 
343 			InputEvent ievent;
344 			ievent.type = InputEvent::SCREEN_DRAG;
345 			ievent.ID = ++last_id;
346 			ievent.device = 0;
347 			ievent.screen_drag.x = pos[0];
348 			ievent.screen_drag.y = pos[1];
349 
350 			/*
351 		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION, pos);
352 		ievent.screen_drag.relative_x = ievent.screen_drag.x - pos[0];
353 		ievent.screen_drag.relative_y = ievent.screen_drag.y - pos[1];
354 		*/
355 
356 			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pos[0]);
357 			ievent.screen_drag.index = pos[0];
358 
359 			ievent.screen_drag.relative_x = ievent.screen_drag.x - last_touch_x[ievent.screen_drag.index];
360 			ievent.screen_drag.relative_y = ievent.screen_drag.y - last_touch_y[ievent.screen_drag.index];
361 
362 			last_touch_x[ievent.screen_drag.index] = ievent.screen_drag.x;
363 			last_touch_y[ievent.screen_drag.index] = ievent.screen_drag.y;
364 
365 			Point2 mpos(ievent.screen_drag.x, ievent.screen_drag.y);
366 			Point2 mrel(ievent.screen_drag.relative_x, ievent.screen_drag.relative_y);
367 
368 			input->parse_input_event(ievent);
369 
370 			if (ievent.screen_touch.index == 0) {
371 
372 				InputEvent ievent;
373 				ievent.type = InputEvent::MOUSE_MOTION;
374 				ievent.ID = ++last_id;
375 				ievent.device = 0;
376 				ievent.mouse_motion.x = ievent.mouse_motion.global_x = mpos.x;
377 				ievent.mouse_motion.y = ievent.mouse_motion.global_y = mpos.y;
378 				input->set_mouse_pos(Point2(ievent.mouse_motion.x, ievent.mouse_motion.y));
379 				ievent.mouse_motion.speed_x = input->get_mouse_speed().x;
380 				ievent.mouse_motion.speed_y = input->get_mouse_speed().y;
381 				ievent.mouse_motion.relative_x = mrel.x;
382 				ievent.mouse_motion.relative_y = mrel.y;
383 				ievent.mouse_motion.button_mask = 1; // pressed
384 
385 				input->parse_input_event(ievent);
386 			};
387 		} break;
388 
389 		case SCREEN_EVENT_KEYBOARD: {
390 
391 			InputEvent ievent;
392 			ievent.type = InputEvent::KEY;
393 			ievent.ID = ++last_id;
394 			ievent.device = 0;
395 			int val = 0;
396 			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SCAN, &val);
397 			ievent.key.scancode = val;
398 			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &val);
399 			ievent.key.unicode = val;
400 			if (val == 61448) {
401 				ievent.key.scancode = KEY_BACKSPACE;
402 				ievent.key.unicode = KEY_BACKSPACE;
403 			};
404 			if (val == 61453) {
405 				ievent.key.scancode = KEY_ENTER;
406 				ievent.key.unicode = KEY_ENTER;
407 			};
408 
409 			int flags;
410 			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
411 			ievent.key.pressed = flags & 1; // bit 1 is pressed apparently
412 
413 			int mod;
414 			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
415 
416 			input->parse_input_event(ievent);
417 		} break;
418 
419 		default:
420 			break;
421 	}
422 };
423 
handle_accelerometer()424 void OSBB10::handle_accelerometer() {
425 
426 	if (!accel_supported)
427 		return;
428 
429 	if (!fullscreen)
430 		return;
431 
432 	double force_x, force_y, force_z;
433 	accelerometer_read_forces(&force_x, &force_y, &force_z);
434 	Vector3 accel = Vector3(force_x, flip_accelerometer ? force_y : -force_y, force_z);
435 	input->set_accelerometer(accel);
436 	// rotate 90 degrees
437 	//input->set_accelerometer(Vector3(force_y, flip_accelerometer?force_x:(-force_x), force_z));
438 };
439 
_resize(bps_event_t * event)440 void OSBB10::_resize(bps_event_t *event) {
441 
442 	int angle = navigator_event_get_orientation_angle(event);
443 	bbutil_rotate_screen_surface(angle);
444 
445 	EGLint surface_width, surface_height;
446 	eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width);
447 	eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height);
448 
449 	VideoMode mode;
450 	mode.width = surface_width;
451 	mode.height = surface_height;
452 	mode.fullscreen = true;
453 	mode.resizable = false;
454 	set_video_mode(mode);
455 };
456 
process_events()457 void OSBB10::process_events() {
458 
459 	handle_accelerometer();
460 
461 	bps_event_t *event = NULL;
462 
463 	do {
464 		int rc = bps_get_event(&event, 0);
465 		assert(rc == BPS_SUCCESS);
466 
467 		if (!event) break;
468 
469 #ifdef BB10_SCORELOOP_ENABLED
470 		ScoreloopBB10 *sc = Globals::get_singleton()->get_singleton_object("Scoreloop")->cast_to<ScoreloopBB10>();
471 		if (sc->handle_event(event))
472 			continue;
473 #endif
474 
475 #ifdef PAYMENT_SERVICE_ENABLED
476 		if (payment_service->handle_event(event))
477 			continue;
478 #endif
479 
480 		int domain = bps_event_get_domain(event);
481 		if (domain == screen_get_domain()) {
482 
483 			handle_screen_event(event);
484 
485 		} else if (domain == navigator_get_domain()) {
486 
487 			if (NAVIGATOR_EXIT == bps_event_get_code(event)) {
488 				if (main_loop)
489 					main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
490 				bps_event_destroy(event);
491 				exit(0);
492 				return;
493 				/*
494 			} else if (bps_event_get_code(event) == NAVIGATOR_ORIENTATION_CHECK) {
495 
496 				int angle = navigator_event_get_orientation_angle(event);
497 				navigator_orientation_check_response(event, false);
498 
499 			} else if (bps_event_get_code(event) == NAVIGATOR_ORIENTATION) {
500 
501 				_resize(event);
502 			*/
503 			} else if (bps_event_get_code(event) == NAVIGATOR_WINDOW_STATE) {
504 
505 				int state = navigator_event_get_window_state(event);
506 				bool was_fullscreen = fullscreen;
507 				minimized = state == NAVIGATOR_WINDOW_INVISIBLE;
508 				fullscreen = state == NAVIGATOR_WINDOW_FULLSCREEN;
509 				set_low_processor_usage_mode(!fullscreen);
510 				if (fullscreen != was_fullscreen) {
511 					if (fullscreen) {
512 						audio_server->set_fx_global_volume_scale(fullscreen_mixer_volume);
513 						audio_server->set_stream_global_volume_scale(fullscreen_stream_volume);
514 					} else {
515 						fullscreen_mixer_volume = audio_server->get_fx_global_volume_scale();
516 						fullscreen_stream_volume = audio_server->get_stream_global_volume_scale();
517 						audio_server->set_fx_global_volume_scale(0);
518 						audio_server->set_stream_global_volume_scale(0);
519 					};
520 				};
521 			};
522 		} else if (domain == audiodevice_get_domain()) {
523 
524 			const char *audiodevice_path = audiodevice_event_get_path(event);
525 			printf("************* got audiodevice event, path %s\n", audiodevice_path);
526 			audio_driver->finish();
527 			audio_driver->init(audiodevice_path);
528 			audio_driver->start();
529 		};
530 
531 		//bps_event_destroy(event);
532 	} while (event);
533 };
534 
has_virtual_keyboard() const535 bool OSBB10::has_virtual_keyboard() const {
536 
537 	return true;
538 };
539 
show_virtual_keyboard(const String & p_existing_text,const Rect2 & p_screen_rect)540 void OSBB10::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect) {
541 
542 	virtualkeyboard_show();
543 };
544 
hide_virtual_keyboard()545 void OSBB10::hide_virtual_keyboard() {
546 
547 	virtualkeyboard_hide();
548 };
549 
run()550 void OSBB10::run() {
551 
552 	if (!main_loop)
553 		return;
554 
555 	main_loop->init();
556 
557 	int flip = bbutil_is_flipped();
558 	int rot = bbutil_get_rotation();
559 	flip_accelerometer = rot == 90;
560 	printf("**************** rot is %i, flip %i\n", rot, (int)flip_accelerometer);
561 	/*
562 	orientation_direction_t orientation;
563 	int angle;
564 	orientation_get(&orientation, &angle);
565 	printf("******************** orientation %i, %i, %i\n", orientation, ORIENTATION_BOTTOM_UP, ORIENTATION_TOP_UP);
566 	if (orientation == ORIENTATION_BOTTOM_UP) {
567 		flip_accelerometer = true;
568 	};
569 	*/
570 
571 	while (true) {
572 
573 		process_events(); // get rid of pending events
574 		if (Main::iteration() == true)
575 			break;
576 		bbutil_swap();
577 		//#ifdef DEBUG_ENABLED
578 		fflush(stdout);
579 		//#endif
580 	};
581 
582 	main_loop->finish();
583 };
584 
has_touchscreen_ui_hint() const585 bool OSBB10::has_touchscreen_ui_hint() const {
586 
587 	return true;
588 }
589 
shell_open(String p_uri)590 Error OSBB10::shell_open(String p_uri) {
591 
592 	char *msg = NULL;
593 	int ret = navigator_invoke(p_uri.utf8().get_data(), &msg);
594 
595 	return ret == BPS_SUCCESS ? OK : FAILED;
596 };
597 
get_data_dir() const598 String OSBB10::get_data_dir() const {
599 
600 	return data_dir;
601 };
602 
get_window_size() const603 Size2 OSBB10::get_window_size() const {
604 	return Vector2(default_videomode.width, default_videomode.height);
605 }
606 
OSBB10()607 OSBB10::OSBB10() {
608 
609 	main_loop = NULL;
610 	last_id = 1;
611 	minimized = false;
612 	fullscreen = true;
613 	flip_accelerometer = true;
614 	fullscreen_mixer_volume = 1;
615 	fullscreen_stream_volume = 1;
616 
617 	printf("godot bb10!\n");
618 	getcwd(launch_dir, sizeof(launch_dir));
619 	printf("launch dir %s\n", launch_dir);
620 	chdir("app/native");
621 	launch_dir_ptr = launch_dir;
622 }
623 
~OSBB10()624 OSBB10::~OSBB10() {
625 }
626