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