/*************************************************************************/ /* os_bb10.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "os_bb10.h" #include "core/os/dir_access.h" #include "drivers/gles2/rasterizer_gles2.h" #include "servers/visual/visual_server_raster.h" #include "bbutil.h" #include "core/globals.h" #include "core/os/keyboard.h" #include "main/main.h" #include #include #include #include "bps/accelerometer.h" #include "bps/audiodevice.h" #include "bps/bps.h" #include "bps/navigator.h" #include "bps/orientation.h" #include "bps/screen.h" #include "bps/virtualkeyboard.h" #ifdef BB10_SCORELOOP_ENABLED #include "modules/scoreloop/scoreloop_bb10.h" #endif static char launch_dir[512]; char *launch_dir_ptr; int OSBB10::get_video_driver_count() const { return 1; } const char *OSBB10::get_video_driver_name(int p_driver) const { return "GLES2"; } OS::VideoMode OSBB10::get_default_video_mode() const { return OS::VideoMode(); } int OSBB10::get_audio_driver_count() const { return 1; } const char *OSBB10::get_audio_driver_name(int p_driver) const { return "BB10"; } void OSBB10::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { data_dir = getenv("HOME"); //Create a screen context that will be used to create an EGL surface to to receive libscreen events screen_create_context(&screen_cxt, 0); //Initialize BPS library bps_initialize(); //Use utility code to initialize EGL for 2D rendering with GL ES 1.1 enum RENDERING_API api = GL_ES_2; #ifdef BB10_LGLES_OVERRIDE api = GL_ES_1; #endif if (EXIT_SUCCESS != bbutil_init(screen_cxt, api)) { bbutil_terminate(); screen_destroy_context(screen_cxt); return; }; EGLint surface_width, surface_height; eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width); eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height); printf("screen size: %ix%i\n", surface_width, surface_height); VideoMode mode; mode.width = surface_width; mode.height = surface_height; mode.fullscreen = true; mode.resizable = false; set_video_mode(mode); //Signal BPS library that navigator and screen events will be requested screen_request_events(screen_cxt); navigator_request_events(0); virtualkeyboard_request_events(0); audiodevice_request_events(0); #ifdef DEBUG_ENABLED bps_set_verbosity(3); #endif accel_supported = accelerometer_is_supported(); if (accel_supported) accelerometer_set_update_frequency(FREQ_40_HZ); pitch = 0; roll = 0; #ifdef BB10_LGLES_OVERRIDE rasterizer = memnew(RasterizerGLES1(false)); #else rasterizer = memnew(RasterizerGLES2(false, false)); #endif visual_server = memnew(VisualServerRaster(rasterizer)); visual_server->init(); visual_server->cursor_set_visible(false, 0); audio_driver = memnew(AudioDriverBB10); audio_driver->set_singleton(); audio_driver->init(NULL); sample_manager = memnew(SampleManagerMallocSW); audio_server = memnew(AudioServerSW(sample_manager)); audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR, false); audio_server->init(); spatial_sound_server = memnew(SpatialSoundServerSW); spatial_sound_server->init(); spatial_sound_2d_server = memnew(SpatialSound2DServerSW); spatial_sound_2d_server->init(); // physics_server = memnew(PhysicsServerSW); physics_server->init(); physics_2d_server = memnew(Physics2DServerSW); physics_2d_server->init(); input = memnew(InputDefault); #ifdef PAYMENT_SERVICE_ENABLED payment_service = memnew(PaymentService); Globals::get_singleton()->add_singleton(Globals::Singleton("InAppStore", payment_service)); #endif } void OSBB10::set_main_loop(MainLoop *p_main_loop) { input->set_main_loop(p_main_loop); main_loop = p_main_loop; } void OSBB10::delete_main_loop() { memdelete(main_loop); main_loop = NULL; } void OSBB10::finalize() { if (main_loop) memdelete(main_loop); main_loop = NULL; spatial_sound_server->finish(); memdelete(spatial_sound_server); spatial_sound_2d_server->finish(); memdelete(spatial_sound_2d_server); //if (debugger_connection_console) { // memdelete(debugger_connection_console); //} memdelete(sample_manager); audio_server->finish(); memdelete(audio_server); visual_server->finish(); memdelete(visual_server); memdelete(rasterizer); physics_server->finish(); memdelete(physics_server); physics_2d_server->finish(); memdelete(physics_2d_server); #ifdef PAYMENT_SERVICE_ENABLED memdelete(payment_service); #endif memdelete(input); bbutil_terminate(); screen_destroy_context(screen_cxt); bps_shutdown(); } void OSBB10::set_mouse_show(bool p_show) { //android has no mouse... } void OSBB10::set_mouse_grab(bool p_grab) { //it really has no mouse...! } bool OSBB10::is_mouse_grab_enabled() const { //*sigh* technology has evolved so much since i was a kid.. return false; } Point2 OSBB10::get_mouse_pos() const { return Point2(); } int OSBB10::get_mouse_button_state() const { return 0; } void OSBB10::set_window_title(const String &p_title) { } //interesting byt not yet //void set_clipboard(const String& p_text); //String get_clipboard() const; void OSBB10::set_video_mode(const VideoMode &p_video_mode, int p_screen) { default_videomode = p_video_mode; } OS::VideoMode OSBB10::get_video_mode(int p_screen) const { return default_videomode; } void OSBB10::get_fullscreen_mode_list(List *p_list, int p_screen) const { p_list->push_back(default_videomode); } String OSBB10::get_name() { return "BlackBerry 10"; } MainLoop *OSBB10::get_main_loop() const { return main_loop; } bool OSBB10::can_draw() const { return !minimized; } void OSBB10::set_cursor_shape(CursorShape p_shape) { //android really really really has no mouse.. how amazing.. } void OSBB10::handle_screen_event(bps_event_t *event) { screen_event_t screen_event = screen_event_get_event(event); int screen_val; screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &screen_val); int pos[2]; switch (screen_val) { case SCREEN_EVENT_MTOUCH_TOUCH: case SCREEN_EVENT_MTOUCH_RELEASE: { screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_POSITION, pos); InputEvent ievent; ievent.type = InputEvent::SCREEN_TOUCH; ievent.ID = ++last_id; ievent.device = 0; ievent.screen_touch.pressed = (screen_val == SCREEN_EVENT_MTOUCH_TOUCH); ievent.screen_touch.x = pos[0]; ievent.screen_touch.y = pos[1]; Point2 mpos(ievent.screen_touch.x, ievent.screen_touch.y); screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pos[0]); ievent.screen_touch.index = pos[0]; last_touch_x[pos[0]] = ievent.screen_touch.x; last_touch_y[pos[0]] = ievent.screen_touch.y; input->parse_input_event(ievent); if (ievent.screen_touch.index == 0) { InputEvent ievent; ievent.type = InputEvent::MOUSE_BUTTON; ievent.ID = ++last_id; ievent.device = 0; ievent.mouse_button.pressed = (screen_val == SCREEN_EVENT_MTOUCH_TOUCH); ievent.mouse_button.button_index = BUTTON_LEFT; ievent.mouse_button.doubleclick = 0; ievent.mouse_button.x = ievent.mouse_button.global_x = mpos.x; ievent.mouse_button.y = ievent.mouse_button.global_y = mpos.y; input->parse_input_event(ievent); }; } break; case SCREEN_EVENT_MTOUCH_MOVE: { screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_POSITION, pos); InputEvent ievent; ievent.type = InputEvent::SCREEN_DRAG; ievent.ID = ++last_id; ievent.device = 0; ievent.screen_drag.x = pos[0]; ievent.screen_drag.y = pos[1]; /* screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION, pos); ievent.screen_drag.relative_x = ievent.screen_drag.x - pos[0]; ievent.screen_drag.relative_y = ievent.screen_drag.y - pos[1]; */ screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pos[0]); ievent.screen_drag.index = pos[0]; ievent.screen_drag.relative_x = ievent.screen_drag.x - last_touch_x[ievent.screen_drag.index]; ievent.screen_drag.relative_y = ievent.screen_drag.y - last_touch_y[ievent.screen_drag.index]; last_touch_x[ievent.screen_drag.index] = ievent.screen_drag.x; last_touch_y[ievent.screen_drag.index] = ievent.screen_drag.y; Point2 mpos(ievent.screen_drag.x, ievent.screen_drag.y); Point2 mrel(ievent.screen_drag.relative_x, ievent.screen_drag.relative_y); input->parse_input_event(ievent); if (ievent.screen_touch.index == 0) { InputEvent ievent; ievent.type = InputEvent::MOUSE_MOTION; ievent.ID = ++last_id; ievent.device = 0; ievent.mouse_motion.x = ievent.mouse_motion.global_x = mpos.x; ievent.mouse_motion.y = ievent.mouse_motion.global_y = mpos.y; input->set_mouse_pos(Point2(ievent.mouse_motion.x, ievent.mouse_motion.y)); ievent.mouse_motion.speed_x = input->get_mouse_speed().x; ievent.mouse_motion.speed_y = input->get_mouse_speed().y; ievent.mouse_motion.relative_x = mrel.x; ievent.mouse_motion.relative_y = mrel.y; ievent.mouse_motion.button_mask = 1; // pressed input->parse_input_event(ievent); }; } break; case SCREEN_EVENT_KEYBOARD: { InputEvent ievent; ievent.type = InputEvent::KEY; ievent.ID = ++last_id; ievent.device = 0; int val = 0; screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SCAN, &val); ievent.key.scancode = val; screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &val); ievent.key.unicode = val; if (val == 61448) { ievent.key.scancode = KEY_BACKSPACE; ievent.key.unicode = KEY_BACKSPACE; }; if (val == 61453) { ievent.key.scancode = KEY_ENTER; ievent.key.unicode = KEY_ENTER; }; int flags; screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_FLAGS, &flags); ievent.key.pressed = flags & 1; // bit 1 is pressed apparently int mod; screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_MODIFIERS, &mod); input->parse_input_event(ievent); } break; default: break; } }; void OSBB10::handle_accelerometer() { if (!accel_supported) return; if (!fullscreen) return; double force_x, force_y, force_z; accelerometer_read_forces(&force_x, &force_y, &force_z); Vector3 accel = Vector3(force_x, flip_accelerometer ? force_y : -force_y, force_z); input->set_accelerometer(accel); // rotate 90 degrees //input->set_accelerometer(Vector3(force_y, flip_accelerometer?force_x:(-force_x), force_z)); }; void OSBB10::_resize(bps_event_t *event) { int angle = navigator_event_get_orientation_angle(event); bbutil_rotate_screen_surface(angle); EGLint surface_width, surface_height; eglQuerySurface(egl_disp, egl_surf, EGL_WIDTH, &surface_width); eglQuerySurface(egl_disp, egl_surf, EGL_HEIGHT, &surface_height); VideoMode mode; mode.width = surface_width; mode.height = surface_height; mode.fullscreen = true; mode.resizable = false; set_video_mode(mode); }; void OSBB10::process_events() { handle_accelerometer(); bps_event_t *event = NULL; do { int rc = bps_get_event(&event, 0); assert(rc == BPS_SUCCESS); if (!event) break; #ifdef BB10_SCORELOOP_ENABLED ScoreloopBB10 *sc = Globals::get_singleton()->get_singleton_object("Scoreloop")->cast_to(); if (sc->handle_event(event)) continue; #endif #ifdef PAYMENT_SERVICE_ENABLED if (payment_service->handle_event(event)) continue; #endif int domain = bps_event_get_domain(event); if (domain == screen_get_domain()) { handle_screen_event(event); } else if (domain == navigator_get_domain()) { if (NAVIGATOR_EXIT == bps_event_get_code(event)) { if (main_loop) main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST); bps_event_destroy(event); exit(0); return; /* } else if (bps_event_get_code(event) == NAVIGATOR_ORIENTATION_CHECK) { int angle = navigator_event_get_orientation_angle(event); navigator_orientation_check_response(event, false); } else if (bps_event_get_code(event) == NAVIGATOR_ORIENTATION) { _resize(event); */ } else if (bps_event_get_code(event) == NAVIGATOR_WINDOW_STATE) { int state = navigator_event_get_window_state(event); bool was_fullscreen = fullscreen; minimized = state == NAVIGATOR_WINDOW_INVISIBLE; fullscreen = state == NAVIGATOR_WINDOW_FULLSCREEN; set_low_processor_usage_mode(!fullscreen); if (fullscreen != was_fullscreen) { if (fullscreen) { audio_server->set_fx_global_volume_scale(fullscreen_mixer_volume); audio_server->set_stream_global_volume_scale(fullscreen_stream_volume); } else { fullscreen_mixer_volume = audio_server->get_fx_global_volume_scale(); fullscreen_stream_volume = audio_server->get_stream_global_volume_scale(); audio_server->set_fx_global_volume_scale(0); audio_server->set_stream_global_volume_scale(0); }; }; }; } else if (domain == audiodevice_get_domain()) { const char *audiodevice_path = audiodevice_event_get_path(event); printf("************* got audiodevice event, path %s\n", audiodevice_path); audio_driver->finish(); audio_driver->init(audiodevice_path); audio_driver->start(); }; //bps_event_destroy(event); } while (event); }; bool OSBB10::has_virtual_keyboard() const { return true; }; void OSBB10::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect) { virtualkeyboard_show(); }; void OSBB10::hide_virtual_keyboard() { virtualkeyboard_hide(); }; void OSBB10::run() { if (!main_loop) return; main_loop->init(); int flip = bbutil_is_flipped(); int rot = bbutil_get_rotation(); flip_accelerometer = rot == 90; printf("**************** rot is %i, flip %i\n", rot, (int)flip_accelerometer); /* orientation_direction_t orientation; int angle; orientation_get(&orientation, &angle); printf("******************** orientation %i, %i, %i\n", orientation, ORIENTATION_BOTTOM_UP, ORIENTATION_TOP_UP); if (orientation == ORIENTATION_BOTTOM_UP) { flip_accelerometer = true; }; */ while (true) { process_events(); // get rid of pending events if (Main::iteration() == true) break; bbutil_swap(); //#ifdef DEBUG_ENABLED fflush(stdout); //#endif }; main_loop->finish(); }; bool OSBB10::has_touchscreen_ui_hint() const { return true; } Error OSBB10::shell_open(String p_uri) { char *msg = NULL; int ret = navigator_invoke(p_uri.utf8().get_data(), &msg); return ret == BPS_SUCCESS ? OK : FAILED; }; String OSBB10::get_data_dir() const { return data_dir; }; Size2 OSBB10::get_window_size() const { return Vector2(default_videomode.width, default_videomode.height); } OSBB10::OSBB10() { main_loop = NULL; last_id = 1; minimized = false; fullscreen = true; flip_accelerometer = true; fullscreen_mixer_volume = 1; fullscreen_stream_volume = 1; printf("godot bb10!\n"); getcwd(launch_dir, sizeof(launch_dir)); printf("launch dir %s\n", launch_dir); chdir("app/native"); launch_dir_ptr = launch_dir; } OSBB10::~OSBB10() { }