15 #include "androidGraphicsWindow.h" 16 #include "androidGraphicsStateGuardian.h" 17 #include "config_androiddisplay.h" 18 #include "androidGraphicsPipe.h" 20 #include "graphicsPipe.h" 21 #include "keyboardButton.h" 22 #include "mouseButton.h" 23 #include "clockObject.h" 24 #include "pStatTimer.h" 25 #include "textEncoder.h" 26 #include "throw_event.h" 27 #include "nativeWindowHandle.h" 29 #include "android_native_app_glue.h" 30 #include <android/window.h> 31 #include <android/log.h> 33 extern struct android_app* panda_android_app;
35 TypeHandle AndroidGraphicsWindow::_type_handle;
42 AndroidGraphicsWindow::
50 GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
53 DCAST_INTO_V(android_pipe, _pipe);
55 _egl_display = android_pipe->_egl_display;
58 _app = panda_android_app;
62 add_input_device(device);
70 AndroidGraphicsWindow::
71 ~AndroidGraphicsWindow() {
86 PStatTimer timer(_make_current_pcollector, current_thread);
88 begin_frame_spam(mode);
94 if (_egl_surface == EGL_NO_SURFACE) {
99 DCAST_INTO_R(androidgsg, _gsg,
false);
101 if (eglGetCurrentDisplay() == _egl_display &&
102 eglGetCurrentSurface(EGL_READ) == _egl_surface &&
103 eglGetCurrentSurface(EGL_DRAW) == _egl_surface &&
104 eglGetCurrentContext() == androidgsg->_context) {
109 if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
110 androiddisplay_cat.error() <<
"Failed to call eglMakeCurrent: " 111 << get_egl_error_string(eglGetError()) <<
"\n";
120 androidgsg->reset_if_new();
122 if (mode == FM_render) {
124 clear_cube_map_selection();
128 return _gsg->begin_frame(current_thread);
140 end_frame_spam(mode);
143 if (mode == FM_render) {
148 _gsg->end_frame(current_thread);
150 if (mode == FM_render) {
152 clear_cube_map_selection();
176 if (_egl_surface != EGL_NO_SURFACE) {
177 eglSwapBuffers(_egl_display, _egl_surface);
200 struct android_poll_source* source;
203 while ((looper_id = ALooper_pollAll(0, NULL, &events, (
void**)&source)) >= 0) {
205 if (source != NULL) {
206 source->process(_app, source);
244 uint32_t add_flags = 0;
245 uint32_t del_flags = 0;
246 if (_properties.get_fullscreen()) {
247 add_flags |= AWINDOW_FLAG_FULLSCREEN;
249 del_flags |= AWINDOW_FLAG_FULLSCREEN;
251 ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
264 void AndroidGraphicsWindow::
272 GraphicsWindow::close_window();
282 bool AndroidGraphicsWindow::
294 DCAST_INTO_R(androidgsg, _gsg,
false);
303 assert(_app != NULL);
304 _app->userData =
this;
305 _app->onAppCmd = handle_command;
306 _app->onInputEvent = handle_input_event;
309 while (_app->window == NULL) {
314 if (_egl_surface == EGL_NO_SURFACE) {
319 _properties.set_origin(0, 0);
320 _properties.set_cursor_hidden(
true);
321 _properties.set_undecorated(
true);
324 (_fb_properties, androidgsg->get_gl_renderer())) {
331 androiddisplay_cat.error() <<
"open_window done\n";
341 void AndroidGraphicsWindow::
343 if (_egl_surface != EGL_NO_SURFACE) {
344 if (!eglDestroySurface(_egl_display, _egl_surface)) {
345 androiddisplay_cat.error() <<
"Failed to destroy surface: " 346 << get_egl_error_string(eglGetError()) <<
"\n";
348 _egl_surface = EGL_NO_SURFACE;
354 DCAST_INTO_V(androidgsg, _gsg);
364 bool AndroidGraphicsWindow::
367 DCAST_INTO_R(androidgsg, _gsg,
false);
370 ANativeWindow_setBuffersGeometry(_app->window, 0, 0, androidgsg->_format);
373 uint32_t add_flags = 0;
374 uint32_t del_flags = 0;
375 if (_properties.get_fullscreen()) {
376 add_flags |= AWINDOW_FLAG_FULLSCREEN;
378 del_flags |= AWINDOW_FLAG_FULLSCREEN;
380 ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
383 _egl_surface = eglCreateWindowSurface(_egl_display, androidgsg->_fbconfig, _app->window, NULL);
384 if (eglGetError() != EGL_SUCCESS) {
385 androiddisplay_cat.error()
386 <<
"Failed to create window surface.\n";
391 if (androidgsg->_context == EGL_NO_CONTEXT) {
392 androiddisplay_cat.error() <<
"creating context\n";
399 if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
400 androiddisplay_cat.error() <<
"Failed to call eglMakeCurrent: " 401 << get_egl_error_string(eglGetError()) <<
"\n";
409 androidgsg->reset_if_new();
410 if (!androidgsg->is_valid()) {
423 void AndroidGraphicsWindow::
424 handle_command(
struct android_app *app, int32_t command) {
426 window->ns_handle_command(command);
434 void AndroidGraphicsWindow::
435 ns_handle_command(int32_t command) {
439 case APP_CMD_SAVE_STATE:
445 case APP_CMD_INIT_WINDOW:
447 if (_app->window != NULL) {
449 properties.
set_size(ANativeWindow_getWidth(_app->window),
450 ANativeWindow_getHeight(_app->window));
452 system_changed_properties(properties);
455 case APP_CMD_CONFIG_CHANGED:
456 properties.
set_size(ANativeWindow_getWidth(_app->window),
457 ANativeWindow_getHeight(_app->window));
458 system_changed_properties(properties);
460 case APP_CMD_TERM_WINDOW:
463 system_changed_properties(properties);
465 case APP_CMD_WINDOW_RESIZED:
466 properties.
set_size(ANativeWindow_getWidth(_app->window),
467 ANativeWindow_getHeight(_app->window));
469 case APP_CMD_WINDOW_REDRAW_NEEDED:
471 case APP_CMD_CONTENT_RECT_CHANGED:
472 properties.
set_origin(_app->contentRect.left, _app->contentRect.top);
473 properties.
set_size(_app->contentRect.right - _app->contentRect.left,
474 _app->contentRect.bottom - _app->contentRect.top);
475 system_changed_properties(properties);
477 case APP_CMD_GAINED_FOCUS:
479 system_changed_properties(properties);
481 case APP_CMD_LOST_FOCUS:
483 system_changed_properties(properties);
485 case APP_CMD_DESTROY:
488 system_changed_properties(properties);
499 int32_t AndroidGraphicsWindow::
500 handle_input_event(
struct android_app* app, AInputEvent *event) {
503 int32_t event_type = AInputEvent_getType(event);
504 switch (event_type) {
505 case AINPUT_EVENT_TYPE_KEY:
506 return window->handle_key_event(event);
507 case AINPUT_EVENT_TYPE_MOTION:
508 return window->handle_motion_event(event);
518 int32_t AndroidGraphicsWindow::
519 handle_key_event(
const AInputEvent *event) {
541 int32_t keycode = AKeyEvent_getKeyCode(event);
545 androiddisplay_cat.warning()
546 <<
"Unknown keycode: " << keycode <<
"\n";
551 int32_t action = AKeyEvent_getAction(event);
552 if (action == AKEY_EVENT_ACTION_DOWN) {
553 _input_devices[0].button_down(button);
554 }
else if (action == AKEY_EVENT_ACTION_UP) {
555 _input_devices[0].button_up(button);
567 int32_t AndroidGraphicsWindow::
568 handle_motion_event(
const AInputEvent *event) {
569 int32_t action = AMotionEvent_getAction(event);
570 action &= AMOTION_EVENT_ACTION_MASK;
572 if (action == AMOTION_EVENT_ACTION_DOWN) {
574 }
else if (action == AMOTION_EVENT_ACTION_UP) {
578 float x = AMotionEvent_getX(event, 0) - _app->contentRect.left;
579 float y = AMotionEvent_getY(event, 0) - _app->contentRect.top;
581 _input_devices[0].set_pointer_in_window(x, y);
594 map_button(int32_t keycode) {
596 case AKEYCODE_SOFT_LEFT:
597 case AKEYCODE_SOFT_RIGHT:
601 case AKEYCODE_ENDCALL:
627 case AKEYCODE_DPAD_UP:
628 return KeyboardButton::up();
629 case AKEYCODE_DPAD_DOWN:
630 return KeyboardButton::down();
631 case AKEYCODE_DPAD_LEFT:
632 return KeyboardButton::left();
633 case AKEYCODE_DPAD_RIGHT:
634 return KeyboardButton::right();
635 case AKEYCODE_DPAD_CENTER:
636 case AKEYCODE_VOLUME_UP:
637 case AKEYCODE_VOLUME_DOWN:
639 case AKEYCODE_CAMERA:
696 case AKEYCODE_PERIOD:
698 case AKEYCODE_ALT_LEFT:
699 return KeyboardButton::lalt();
700 case AKEYCODE_ALT_RIGHT:
701 return KeyboardButton::ralt();
702 case AKEYCODE_SHIFT_LEFT:
703 return KeyboardButton::lshift();
704 case AKEYCODE_SHIFT_RIGHT:
705 return KeyboardButton::rshift();
707 return KeyboardButton::tab();
709 return KeyboardButton::space();
711 case AKEYCODE_EXPLORER:
712 case AKEYCODE_ENVELOPE:
715 return KeyboardButton::enter();
717 return KeyboardButton::del();
722 case AKEYCODE_EQUALS:
724 case AKEYCODE_LEFT_BRACKET:
726 case AKEYCODE_RIGHT_BRACKET:
728 case AKEYCODE_BACKSLASH:
730 case AKEYCODE_SEMICOLON:
732 case AKEYCODE_APOSTROPHE:
739 case AKEYCODE_HEADSETHOOK:
745 case AKEYCODE_NOTIFICATION:
746 case AKEYCODE_SEARCH:
747 case AKEYCODE_MEDIA_PLAY_PAUSE:
748 case AKEYCODE_MEDIA_STOP:
749 case AKEYCODE_MEDIA_NEXT:
750 case AKEYCODE_MEDIA_PREVIOUS:
751 case AKEYCODE_MEDIA_REWIND:
752 case AKEYCODE_MEDIA_FAST_FORWARD:
755 case AKEYCODE_PAGE_UP:
756 return KeyboardButton::page_up();
757 case AKEYCODE_PAGE_DOWN:
758 return KeyboardButton::page_down();
759 case AKEYCODE_PICTSYMBOLS:
760 case AKEYCODE_SWITCH_CHARSET:
761 case AKEYCODE_BUTTON_A:
762 case AKEYCODE_BUTTON_B:
763 case AKEYCODE_BUTTON_C:
764 case AKEYCODE_BUTTON_X:
765 case AKEYCODE_BUTTON_Y:
766 case AKEYCODE_BUTTON_Z:
767 case AKEYCODE_BUTTON_L1:
768 case AKEYCODE_BUTTON_R1:
769 case AKEYCODE_BUTTON_L2:
770 case AKEYCODE_BUTTON_R2:
771 case AKEYCODE_BUTTON_THUMBL:
772 case AKEYCODE_BUTTON_THUMBR:
773 case AKEYCODE_BUTTON_START:
774 case AKEYCODE_BUTTON_SELECT:
775 case AKEYCODE_BUTTON_MODE:
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e...
virtual void end_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread after rendering is completed for a given frame...
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
bool create_context()
Creates the context based on the config previously obtained in choose_pixel_format.
void set_size(const LVector2i &size)
Specifies the requested size of the window, in pixels.
void choose_pixel_format(const FrameBufferProperties &properties, bool need_pbuffer, bool need_pixmap)
Selects a visual or fbconfig for all the windows and buffers that use this gsg.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
An interface to manage Android windows and their appropriate EGL surfaces.
A window, fullscreen or on a desktop, into which a graphics device sends its output for interactive d...
bool has_fullscreen() const
Returns true if set_fullscreen() has been specified.
A container for the various kinds of properties we might ask to have on a graphics window before we o...
bool get_fullscreen() const
Returns true if the window is in fullscreen mode.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
An object to create GraphicsOutputs that share a particular 3-D API.
bool verify_hardware_software(const FrameBufferProperties &props, const string &renderer) const
Validates that the properties represent the desired kind of renderer (hardware or software)...
void set_origin(const LPoint2i &origin)
Specifies the origin on the screen (in pixels, relative to the top-left corner) at which the window s...
This is a base class for the various different classes that represent the result of a frame of render...
virtual bool begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame...
void set_foreground(bool foreground)
Specifies whether the window should be opened in the foreground (true), or left in the background (fa...
A thread; that is, a lightweight process.
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
void set_minimized(bool minimized)
Specifies whether the window should be created minimized (true), or normal (false).
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
Encapsulates all the communication with a particular instance of a given rendering backend...
void destroy_context()
Destroys the context previously created by create_context.
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
This class is the main interface to controlling the render process.
TypeHandle is the identifier used to differentiate C++ class types.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
void set_open(bool open)
Specifies whether the window should be open.
void clear_fullscreen()
Removes the fullscreen specification from the properties.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.