28 #include "android_native_app_glue.h"
29 #include <android/window.h>
30 #include <android/log.h>
32 extern IMPORT_CLASS
struct android_app* panda_android_app;
34 TypeHandle AndroidGraphicsWindow::_type_handle;
39 AndroidGraphicsWindow::
41 const std::string &name,
47 GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host),
48 _mouse_button_state(0)
51 DCAST_INTO_V(android_pipe, _pipe);
53 _egl_display = android_pipe->_egl_display;
56 _app = panda_android_app;
59 add_input_device(device);
66 AndroidGraphicsWindow::
67 ~AndroidGraphicsWindow() {
79 PStatTimer timer(_make_current_pcollector, current_thread);
81 begin_frame_spam(mode);
82 if (_gsg ==
nullptr) {
87 if (_egl_surface == EGL_NO_SURFACE) {
92 DCAST_INTO_R(androidgsg, _gsg,
false);
94 if (eglGetCurrentDisplay() == _egl_display &&
95 eglGetCurrentSurface(EGL_READ) == _egl_surface &&
96 eglGetCurrentSurface(EGL_DRAW) == _egl_surface &&
97 eglGetCurrentContext() == androidgsg->_context) {
102 if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
103 androiddisplay_cat.error() <<
"Failed to call eglMakeCurrent: "
113 androidgsg->reset_if_new();
115 if (mode == FM_render) {
117 clear_cube_map_selection();
121 return _gsg->begin_frame(current_thread);
131 end_frame_spam(mode);
132 nassertv(_gsg !=
nullptr);
134 if (mode == FM_render) {
139 _gsg->end_frame(current_thread);
141 if (mode == FM_render) {
143 clear_cube_map_selection();
156 if (_gsg !=
nullptr && _flip_ready) {
164 if (_egl_surface != EGL_NO_SURFACE) {
165 eglSwapBuffers(_egl_display, _egl_surface);
185 struct android_poll_source* source;
188 while ((looper_id = ALooper_pollAll(0,
nullptr, &events, (
void**)&source)) >= 0) {
190 if (source !=
nullptr) {
191 source->process(_app, source);
210 if (_pipe ==
nullptr) {
224 uint32_t add_flags = 0;
225 uint32_t del_flags = 0;
226 if (_properties.get_fullscreen()) {
227 add_flags |= AWINDOW_FLAG_FULLSCREEN;
229 del_flags |= AWINDOW_FLAG_FULLSCREEN;
231 ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
241 void AndroidGraphicsWindow::
245 if (_gsg !=
nullptr) {
249 GraphicsWindow::close_window();
251 nassertv(_app !=
nullptr);
252 if (_app->userData ==
this) {
253 _app->userData =
nullptr;
254 _app->onAppCmd =
nullptr;
255 _app->onInputEvent =
nullptr;
263 bool AndroidGraphicsWindow::
275 DCAST_INTO_R(androidgsg, _gsg,
false);
284 assert(_app !=
nullptr);
285 _app->userData =
this;
286 _app->onAppCmd = handle_command;
287 _app->onInputEvent = handle_input_event;
290 while (_app->window ==
nullptr) {
295 if (_egl_surface == EGL_NO_SURFACE) {
300 _properties.set_origin(0, 0);
301 _properties.set_cursor_hidden(
true);
302 _properties.set_undecorated(
true);
305 (_fb_properties, androidgsg->get_gl_renderer())) {
318 void AndroidGraphicsWindow::
320 if (_egl_surface != EGL_NO_SURFACE) {
321 if (!eglDestroySurface(_egl_display, _egl_surface)) {
322 androiddisplay_cat.error() <<
"Failed to destroy surface: "
325 _egl_surface = EGL_NO_SURFACE;
329 if (_gsg !=
nullptr) {
331 DCAST_INTO_V(androidgsg, _gsg);
339 bool AndroidGraphicsWindow::
342 DCAST_INTO_R(androidgsg, _gsg,
false);
345 ANativeWindow_setBuffersGeometry(_app->window, 0, 0, androidgsg->_format);
348 uint32_t add_flags = 0;
349 uint32_t del_flags = 0;
350 if (_properties.get_fullscreen()) {
351 add_flags |= AWINDOW_FLAG_FULLSCREEN;
353 del_flags |= AWINDOW_FLAG_FULLSCREEN;
355 ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
358 _egl_surface = eglCreateWindowSurface(_egl_display, androidgsg->_fbconfig, _app->window,
nullptr);
359 if (eglGetError() != EGL_SUCCESS) {
360 androiddisplay_cat.error()
361 <<
"Failed to create window surface.\n";
366 if (androidgsg->_context == EGL_NO_CONTEXT) {
373 if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
374 androiddisplay_cat.error() <<
"Failed to call eglMakeCurrent: "
382 androidgsg->reset_if_new();
383 if (!androidgsg->is_valid()) {
394 void AndroidGraphicsWindow::
395 handle_command(
struct android_app *app, int32_t command) {
397 if (window !=
nullptr) {
398 window->ns_handle_command(command);
405 void AndroidGraphicsWindow::
406 ns_handle_command(int32_t command) {
410 case APP_CMD_SAVE_STATE:
416 case APP_CMD_INIT_WINDOW:
418 if (_app->window !=
nullptr) {
420 properties.
set_size(ANativeWindow_getWidth(_app->window),
421 ANativeWindow_getHeight(_app->window));
423 system_changed_properties(properties);
426 case APP_CMD_CONFIG_CHANGED:
427 properties.
set_size(ANativeWindow_getWidth(_app->window),
428 ANativeWindow_getHeight(_app->window));
429 system_changed_properties(properties);
431 case APP_CMD_TERM_WINDOW:
434 system_changed_properties(properties);
436 case APP_CMD_WINDOW_RESIZED:
437 properties.
set_size(ANativeWindow_getWidth(_app->window),
438 ANativeWindow_getHeight(_app->window));
440 case APP_CMD_WINDOW_REDRAW_NEEDED:
442 case APP_CMD_CONTENT_RECT_CHANGED:
443 properties.
set_origin(_app->contentRect.left, _app->contentRect.top);
444 properties.
set_size(_app->contentRect.right - _app->contentRect.left,
445 _app->contentRect.bottom - _app->contentRect.top);
446 system_changed_properties(properties);
448 case APP_CMD_GAINED_FOCUS:
450 system_changed_properties(properties);
452 case APP_CMD_LOST_FOCUS:
454 system_changed_properties(properties);
456 case APP_CMD_DESTROY:
459 system_changed_properties(properties);
467 int32_t AndroidGraphicsWindow::
468 handle_input_event(
struct android_app* app, AInputEvent *event) {
471 int32_t event_type = AInputEvent_getType(event);
472 switch (event_type) {
473 case AINPUT_EVENT_TYPE_KEY:
474 return window->handle_key_event(event);
475 case AINPUT_EVENT_TYPE_MOTION:
476 return window->handle_motion_event(event);
484 int32_t AndroidGraphicsWindow::
485 handle_key_event(
const AInputEvent *event) {
507 int32_t keycode = AKeyEvent_getKeyCode(event);
510 if (button == ButtonHandle::none()) {
511 androiddisplay_cat.warning()
512 <<
"Unknown keycode: " << keycode <<
"\n";
517 int32_t action = AKeyEvent_getAction(event);
518 if (action == AKEY_EVENT_ACTION_DOWN) {
519 if (AKeyEvent_getRepeatCount(event) > 0) {
524 }
else if (action == AKEY_EVENT_ACTION_UP) {
535 int32_t AndroidGraphicsWindow::
536 handle_motion_event(
const AInputEvent *event) {
537 int32_t action = AMotionEvent_getAction(event);
538 action &= AMOTION_EVENT_ACTION_MASK;
540 if (action == AMOTION_EVENT_ACTION_DOWN ||
541 action == AMOTION_EVENT_ACTION_UP) {
544 int32_t button_state = AMotionEvent_getButtonState(event);
545 if (button_state == 0 && action == AMOTION_EVENT_ACTION_DOWN) {
546 button_state = AMOTION_EVENT_BUTTON_PRIMARY;
548 int32_t changed = _mouse_button_state ^ button_state;
550 if (changed & AMOTION_EVENT_BUTTON_PRIMARY) {
551 if (button_state & AMOTION_EVENT_BUTTON_PRIMARY) {
557 if (changed & AMOTION_EVENT_BUTTON_SECONDARY) {
558 if (button_state & AMOTION_EVENT_BUTTON_SECONDARY) {
564 _mouse_button_state = button_state;
568 float x = AMotionEvent_getX(event, 0) - _app->contentRect.left;
569 float y = AMotionEvent_getY(event, 0) - _app->contentRect.top;
581 map_button(int32_t keycode) {
583 case AKEYCODE_SOFT_LEFT:
584 case AKEYCODE_SOFT_RIGHT:
588 case AKEYCODE_ENDCALL:
614 case AKEYCODE_DPAD_UP:
615 return KeyboardButton::up();
616 case AKEYCODE_DPAD_DOWN:
617 return KeyboardButton::down();
618 case AKEYCODE_DPAD_LEFT:
619 return KeyboardButton::left();
620 case AKEYCODE_DPAD_RIGHT:
621 return KeyboardButton::right();
622 case AKEYCODE_DPAD_CENTER:
623 case AKEYCODE_VOLUME_UP:
624 case AKEYCODE_VOLUME_DOWN:
626 case AKEYCODE_CAMERA:
683 case AKEYCODE_PERIOD:
685 case AKEYCODE_ALT_LEFT:
686 return KeyboardButton::lalt();
687 case AKEYCODE_ALT_RIGHT:
688 return KeyboardButton::ralt();
689 case AKEYCODE_SHIFT_LEFT:
690 return KeyboardButton::lshift();
691 case AKEYCODE_SHIFT_RIGHT:
692 return KeyboardButton::rshift();
694 return KeyboardButton::tab();
696 return KeyboardButton::space();
698 case AKEYCODE_EXPLORER:
699 case AKEYCODE_ENVELOPE:
702 return KeyboardButton::enter();
704 return KeyboardButton::backspace();
709 case AKEYCODE_EQUALS:
711 case AKEYCODE_LEFT_BRACKET:
713 case AKEYCODE_RIGHT_BRACKET:
715 case AKEYCODE_BACKSLASH:
717 case AKEYCODE_SEMICOLON:
719 case AKEYCODE_APOSTROPHE:
726 case AKEYCODE_HEADSETHOOK:
732 return KeyboardButton::menu();
733 case AKEYCODE_NOTIFICATION:
734 case AKEYCODE_SEARCH:
735 case AKEYCODE_MEDIA_PLAY_PAUSE:
736 case AKEYCODE_MEDIA_STOP:
737 case AKEYCODE_MEDIA_NEXT:
738 case AKEYCODE_MEDIA_PREVIOUS:
739 case AKEYCODE_MEDIA_REWIND:
740 case AKEYCODE_MEDIA_FAST_FORWARD:
743 case AKEYCODE_PAGE_UP:
744 return KeyboardButton::page_up();
745 case AKEYCODE_PAGE_DOWN:
746 return KeyboardButton::page_down();
747 case AKEYCODE_PICTSYMBOLS:
748 case AKEYCODE_SWITCH_CHARSET:
749 case AKEYCODE_BUTTON_A:
750 case AKEYCODE_BUTTON_B:
751 case AKEYCODE_BUTTON_C:
752 case AKEYCODE_BUTTON_X:
753 case AKEYCODE_BUTTON_Y:
754 case AKEYCODE_BUTTON_Z:
755 case AKEYCODE_BUTTON_L1:
756 case AKEYCODE_BUTTON_R1:
757 case AKEYCODE_BUTTON_L2:
758 case AKEYCODE_BUTTON_R2:
759 case AKEYCODE_BUTTON_THUMBL:
760 case AKEYCODE_BUTTON_THUMBR:
761 case AKEYCODE_BUTTON_START:
762 case AKEYCODE_BUTTON_SELECT:
763 case AKEYCODE_BUTTON_MODE:
765 case AKEYCODE_ESCAPE:
766 return KeyboardButton::escape();
767 case AKEYCODE_FORWARD_DEL:
768 return KeyboardButton::del();
769 case AKEYCODE_CTRL_LEFT:
770 return KeyboardButton::lcontrol();
771 case AKEYCODE_CTRL_RIGHT:
772 return KeyboardButton::rcontrol();
773 case AKEYCODE_CAPS_LOCK:
774 return KeyboardButton::caps_lock();
775 case AKEYCODE_SCROLL_LOCK:
776 return KeyboardButton::scroll_lock();
777 case AKEYCODE_META_LEFT:
778 return KeyboardButton::lmeta();
779 case AKEYCODE_META_RIGHT:
780 return KeyboardButton::rmeta();
781 case AKEYCODE_FUNCTION:
784 return KeyboardButton::print_screen();
786 return KeyboardButton::pause();
787 case AKEYCODE_MOVE_HOME:
788 return KeyboardButton::home();
789 case AKEYCODE_MOVE_END:
790 return KeyboardButton::end();
791 case AKEYCODE_INSERT:
792 return KeyboardButton::insert();
794 return KeyboardButton::f1();
796 return KeyboardButton::f2();
798 return KeyboardButton::f3();
800 return KeyboardButton::f4();
802 return KeyboardButton::f5();
804 return KeyboardButton::f6();
806 return KeyboardButton::f7();
808 return KeyboardButton::f8();
810 return KeyboardButton::f9();
812 return KeyboardButton::f10();
814 return KeyboardButton::f11();
816 return KeyboardButton::f12();
817 case AKEYCODE_NUM_LOCK:
818 return KeyboardButton::num_lock();
822 return ButtonHandle::none();
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e....
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
bool create_context()
Creates the context based on the config previously obtained in choose_pixel_format.
void destroy_context()
Destroys the context previously created by create_context.
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.
An interface to manage Android windows and their appropriate EGL surfaces.
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
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.
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
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.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool verify_hardware_software(const FrameBufferProperties &props, const std::string &renderer) const
Validates that the properties represent the desired kind of renderer (hardware or software).
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.
This is a base class for the various different classes that represent the result of a frame of render...
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
An object to create GraphicsOutputs that share a particular 3-D API.
Encapsulates all the communication with a particular instance of a given rendering backend.
A window, fullscreen or on a desktop, into which a graphics device sends its output for interactive d...
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
A thread; that is, a lightweight 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 window before we o...
has_fullscreen
Returns true if set_fullscreen() has been specified.
set_size
Specifies the requested size of the window, in pixels.
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
clear_fullscreen
Removes the fullscreen specification from the properties.
set_foreground
Specifies whether the window should be opened in the foreground (true), or left in the background (fa...
set_open
Specifies whether the window should be open.
get_fullscreen
Returns true if the window is in fullscreen mode.
set_minimized
Specifies whether the window should be created minimized (true), or normal (false).
set_origin
Specifies the origin on the screen (in pixels, relative to the top-left corner) at which the window s...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const std::string get_egl_error_string(int error)
Returns the given EGL error as string.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.