Panda3D
androidGraphicsWindow.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file androidGraphicsWindow.cxx
10  * @author rdb
11  * @date 2013-01-11
12  */
13 
14 #include "androidGraphicsWindow.h"
16 #include "config_androiddisplay.h"
17 #include "androidGraphicsPipe.h"
18 
19 #include "graphicsPipe.h"
20 #include "keyboardButton.h"
21 #include "mouseButton.h"
22 #include "clockObject.h"
23 #include "pStatTimer.h"
24 #include "textEncoder.h"
25 #include "throw_event.h"
26 #include "nativeWindowHandle.h"
27 
28 #include "android_native_app_glue.h"
29 #include <android/window.h>
30 #include <android/log.h>
31 
32 extern IMPORT_CLASS struct android_app* panda_android_app;
33 
34 TypeHandle AndroidGraphicsWindow::_type_handle;
35 
36 /**
37  *
38  */
39 AndroidGraphicsWindow::
40 AndroidGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
41  const std::string &name,
42  const FrameBufferProperties &fb_prop,
43  const WindowProperties &win_prop,
44  int flags,
46  GraphicsOutput *host) :
47  GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host),
48  _mouse_button_state(0)
49 {
50  AndroidGraphicsPipe *android_pipe;
51  DCAST_INTO_V(android_pipe, _pipe);
52 
53  _egl_display = android_pipe->_egl_display;
54  _egl_surface = 0;
55 
56  _app = panda_android_app;
57 
58  PT(GraphicsWindowInputDevice) device = GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse");
59  add_input_device(device);
60  _input = device;
61 }
62 
63 /**
64  *
65  */
66 AndroidGraphicsWindow::
67 ~AndroidGraphicsWindow() {
68  destroy_surface();
69 }
70 
71 /**
72  * This function will be called within the draw thread before beginning
73  * rendering for a given frame. It should do whatever setup is required, and
74  * return true if the frame should be rendered, or false if it should be
75  * skipped.
76  */
78 begin_frame(FrameMode mode, Thread *current_thread) {
79  PStatTimer timer(_make_current_pcollector, current_thread);
80 
81  begin_frame_spam(mode);
82  if (_gsg == nullptr) {
83  return false;
84  }
85 
86  // XXX not open yet.
87  if (_egl_surface == EGL_NO_SURFACE) {
88  return false;
89  }
90 
91  AndroidGraphicsStateGuardian *androidgsg;
92  DCAST_INTO_R(androidgsg, _gsg, false);
93  {
94  if (eglGetCurrentDisplay() == _egl_display &&
95  eglGetCurrentSurface(EGL_READ) == _egl_surface &&
96  eglGetCurrentSurface(EGL_DRAW) == _egl_surface &&
97  eglGetCurrentContext() == androidgsg->_context) {
98  // No need to make the context current again. Short-circuit this
99  // possibly-expensive call.
100  } else {
101  // Need to set the context.
102  if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
103  androiddisplay_cat.error() << "Failed to call eglMakeCurrent: "
104  << get_egl_error_string(eglGetError()) << "\n";
105  }
106  }
107  }
108 
109  // Now that we have made the context current to a window, we can reset the
110  // GSG state if this is the first time it has been used. (We can't just
111  // call reset() when we construct the GSG, because reset() requires having a
112  // current context.)
113  androidgsg->reset_if_new();
114 
115  if (mode == FM_render) {
116  // begin_render_texture();
117  clear_cube_map_selection();
118  }
119 
120  _gsg->set_current_properties(&get_fb_properties());
121  return _gsg->begin_frame(current_thread);
122 }
123 
124 /**
125  * This function will be called within the draw thread after rendering is
126  * completed for a given frame. It should do whatever finalization is
127  * required.
128  */
130 end_frame(FrameMode mode, Thread *current_thread) {
131  end_frame_spam(mode);
132  nassertv(_gsg != nullptr);
133 
134  if (mode == FM_render) {
135  // end_render_texture();
136  copy_to_textures();
137  }
138 
139  _gsg->end_frame(current_thread);
140 
141  if (mode == FM_render) {
142  trigger_flip();
143  clear_cube_map_selection();
144  }
145 }
146 
147 /**
148  * This function will be called within the draw thread after begin_flip() has
149  * been called on all windows, to finish the exchange of the front and back
150  * buffers.
151  *
152  * This should cause the window to wait for the flip, if necessary.
153  */
156  if (_gsg != nullptr && _flip_ready) {
157 
158  // It doesn't appear to be necessary to ensure the graphics context is
159  // current before flipping the windows, and insisting on doing so can be a
160  // significant performance hit.
161 
162  // make_current();
163 
164  if (_egl_surface != EGL_NO_SURFACE) {
165  eglSwapBuffers(_egl_display, _egl_surface);
166  }
167  }
169 }
170 
171 /**
172  * Do whatever processing is necessary to ensure that the window responds to
173  * user events. Also, honor any requests recently made via
174  * request_properties()
175  *
176  * This function is called only within the window thread.
177  */
181 
182  // Read all pending events.
183  int looper_id;
184  int events;
185  struct android_poll_source* source;
186 
187  // Loop until all events are read.
188  while ((looper_id = ALooper_pollAll(0, nullptr, &events, (void**)&source)) >= 0) {
189  // Process this event.
190  if (source != nullptr) {
191  source->process(_app, source);
192  }
193  }
194 }
195 
196 /**
197  * Applies the requested set of properties to the window, if possible, for
198  * instance to request a change in size or minimization status.
199  *
200  * The window properties are applied immediately, rather than waiting until
201  * the next frame. This implies that this method may *only* be called from
202  * within the window thread.
203  *
204  * The return value is true if the properties are set, false if they are
205  * ignored. This is mainly useful for derived classes to implement extensions
206  * to this function.
207  */
210  if (_pipe == nullptr) {
211  // If the pipe is null, we're probably closing down.
213  return;
214  }
215 
217  if (!properties.is_any_specified()) {
218  // The base class has already handled this case.
219  return;
220  }
221 
222  // There's not really much we can change on Android.
223  if (properties.has_fullscreen()) {
224  uint32_t add_flags = 0;
225  uint32_t del_flags = 0;
226  if (_properties.get_fullscreen()) {
227  add_flags |= AWINDOW_FLAG_FULLSCREEN;
228  } else {
229  del_flags |= AWINDOW_FLAG_FULLSCREEN;
230  }
231  ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
232 
233  _properties.set_fullscreen(properties.get_fullscreen());
234  properties.clear_fullscreen();
235  }
236 }
237 
238 /**
239  * Closes the window right now. Called from the window thread.
240  */
241 void AndroidGraphicsWindow::
242 close_window() {
243  destroy_surface();
244 
245  if (_gsg != nullptr) {
246  _gsg.clear();
247  }
248 
249  GraphicsWindow::close_window();
250 
251  nassertv(_app != nullptr);
252  if (_app->userData == this) {
253  _app->userData = nullptr;
254  _app->onAppCmd = nullptr;
255  _app->onInputEvent = nullptr;
256  }
257 }
258 
259 /**
260  * Opens the window right now. Called from the window thread. Returns true
261  * if the window is successfully opened, or false if there was a problem.
262  */
263 bool AndroidGraphicsWindow::
264 open_window() {
265  // GSG CreationInitialization
266  AndroidGraphicsStateGuardian *androidgsg;
267  if (_gsg == 0) {
268  // There is no old gsg. Create a new one.
269  androidgsg = new AndroidGraphicsStateGuardian(_engine, _pipe, nullptr);
270  androidgsg->choose_pixel_format(_fb_properties, false, false);
271  _gsg = androidgsg;
272  } else {
273  // If the old gsg has the wrong pixel format, create a new one that shares
274  // with the old gsg.
275  DCAST_INTO_R(androidgsg, _gsg, false);
276  if (!androidgsg->get_fb_properties().subsumes(_fb_properties)) {
277  androidgsg = new AndroidGraphicsStateGuardian(_engine, _pipe, androidgsg);
278  androidgsg->choose_pixel_format(_fb_properties, false, false);
279  _gsg = androidgsg;
280  }
281  }
282 
283  // Register the callbacks
284  assert(_app != nullptr);
285  _app->userData = this;
286  _app->onAppCmd = handle_command;
287  _app->onInputEvent = handle_input_event;
288 
289  // Wait until Android has opened the window.
290  while (_app->window == nullptr) {
291  process_events();
292  }
293 
294  // create_surface should have been called by now.
295  if (_egl_surface == EGL_NO_SURFACE) {
296  return false;
297  }
298 
299  // Set some other properties.
300  _properties.set_origin(0, 0);
301  _properties.set_cursor_hidden(true);
302  _properties.set_undecorated(true);
303 
305  (_fb_properties, androidgsg->get_gl_renderer())) {
306  close_window();
307  return false;
308  }
309 
310  _fb_properties = androidgsg->get_fb_properties();
311 
312  return true;
313 }
314 
315 /**
316  * Terminates the EGL surface.
317  */
318 void AndroidGraphicsWindow::
319 destroy_surface() {
320  if (_egl_surface != EGL_NO_SURFACE) {
321  if (!eglDestroySurface(_egl_display, _egl_surface)) {
322  androiddisplay_cat.error() << "Failed to destroy surface: "
323  << get_egl_error_string(eglGetError()) << "\n";
324  }
325  _egl_surface = EGL_NO_SURFACE;
326  }
327 
328  // Destroy the current context.
329  if (_gsg != nullptr) {
330  AndroidGraphicsStateGuardian *androidgsg;
331  DCAST_INTO_V(androidgsg, _gsg);
332  androidgsg->destroy_context();
333  }
334 }
335 
336 /**
337  * Creates the EGL surface.
338  */
339 bool AndroidGraphicsWindow::
340 create_surface() {
341  AndroidGraphicsStateGuardian *androidgsg;
342  DCAST_INTO_R(androidgsg, _gsg, false);
343 
344  // Reconfigure the window buffers to match that of our framebuffer config.
345  ANativeWindow_setBuffersGeometry(_app->window, 0, 0, androidgsg->_format);
346 
347  // Set any window flags
348  uint32_t add_flags = 0;
349  uint32_t del_flags = 0;
350  if (_properties.get_fullscreen()) {
351  add_flags |= AWINDOW_FLAG_FULLSCREEN;
352  } else {
353  del_flags |= AWINDOW_FLAG_FULLSCREEN;
354  }
355  ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
356 
357  // Create the EGL surface.
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";
362  return false;
363  }
364 
365  // Create a context.
366  if (androidgsg->_context == EGL_NO_CONTEXT) {
367  if (!androidgsg->create_context()) {
368  return false;
369  }
370  }
371 
372  // Switch to our newly created context.
373  if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
374  androiddisplay_cat.error() << "Failed to call eglMakeCurrent: "
375  << get_egl_error_string(eglGetError()) << "\n";
376  }
377 
378  // Query the size of the surface. EGLint width, height;
379  // eglQuerySurface(_egl_display, _egl_surface, EGL_WIDTH, &width);
380  // eglQuerySurface(_egl_display, _egl_surface, EGL_HEIGHT, &height);
381 
382  androidgsg->reset_if_new();
383  if (!androidgsg->is_valid()) {
384  close_window();
385  return false;
386  }
387 
388  return true;
389 }
390 
391 /**
392  * Android app sends a command from the main thread.
393  */
394 void AndroidGraphicsWindow::
395 handle_command(struct android_app *app, int32_t command) {
396  AndroidGraphicsWindow *window = (AndroidGraphicsWindow *)app->userData;
397  if (window != nullptr) {
398  window->ns_handle_command(command);
399  }
400 }
401 
402 /**
403  * Android app sends a command from the main thread.
404  */
405 void AndroidGraphicsWindow::
406 ns_handle_command(int32_t command) {
407  WindowProperties properties;
408 
409  switch (command) {
410  case APP_CMD_SAVE_STATE:
411  // The system has asked us to save our current state. Do so.
412  // engine->app->savedState = malloc(sizeof(struct saved_state));
413  // *((struct saved_state*)engine->app->savedState) = engine->state;
414  // engine->app->savedStateSize = sizeof(struct saved_state);
415  break;
416  case APP_CMD_INIT_WINDOW:
417  // The window is being shown, get it ready.
418  if (_app->window != nullptr) {
419  create_surface();
420  properties.set_size(ANativeWindow_getWidth(_app->window),
421  ANativeWindow_getHeight(_app->window));
422  properties.set_minimized(false);
423  system_changed_properties(properties);
424  }
425  break;
426  case APP_CMD_CONFIG_CHANGED:
427  properties.set_size(ANativeWindow_getWidth(_app->window),
428  ANativeWindow_getHeight(_app->window));
429  system_changed_properties(properties);
430  break;
431  case APP_CMD_TERM_WINDOW:
432  destroy_surface();
433  properties.set_minimized(true);
434  system_changed_properties(properties);
435  break;
436  case APP_CMD_WINDOW_RESIZED:
437  properties.set_size(ANativeWindow_getWidth(_app->window),
438  ANativeWindow_getHeight(_app->window));
439  break;
440  case APP_CMD_WINDOW_REDRAW_NEEDED:
441  break;
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);
447  break;
448  case APP_CMD_GAINED_FOCUS:
449  properties.set_foreground(true);
450  system_changed_properties(properties);
451  break;
452  case APP_CMD_LOST_FOCUS:
453  properties.set_foreground(false);
454  system_changed_properties(properties);
455  break;
456  case APP_CMD_DESTROY:
457  close_window();
458  properties.set_open(false);
459  system_changed_properties(properties);
460  break;
461  }
462 }
463 
464 /**
465  * Processes an input event. Returns 1 if the event was handled, 0 otherwise.
466  */
467 int32_t AndroidGraphicsWindow::
468 handle_input_event(struct android_app* app, AInputEvent *event) {
469  AndroidGraphicsWindow* window = (AndroidGraphicsWindow*) app->userData;
470 
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);
477  }
478  return 0;
479 }
480 
481 /**
482  * Processes a key event.
483  */
484 int32_t AndroidGraphicsWindow::
485 handle_key_event(const AInputEvent *event) {
486  /*
487  int32_t meta = AKeyEvent_getMetaState(event);
488  if (meta | AMETA_ALT_ON) {
489  _input->button_down(KeyboardButton.alt());
490  }
491  if (meta | AMETA_ALT_LEFT_ON) {
492  _input->button_down(KeyboardButton.lalt());
493  }
494  if (meta | AMETA_ALT_RIGHT_ON) {
495  _input->button_down(KeyboardButton.ralt());
496  }
497  if (meta | AMETA_SHIFT_ON) {
498  _input->button_down(KeyboardButton.shift());
499  }
500  if (meta | AMETA_SHIFT_LEFT_ON) {
501  _input->button_down(KeyboardButton.lshift());
502  }
503  if (meta | AMETA_SHIFT_RIGHT_ON) {
504  _input->button_down(KeyboardButton.rshift());
505  }*/
506 
507  int32_t keycode = AKeyEvent_getKeyCode(event);
508  ButtonHandle button = map_button(keycode);
509 
510  if (button == ButtonHandle::none()) {
511  androiddisplay_cat.warning()
512  << "Unknown keycode: " << keycode << "\n";
513  return 0;
514  }
515 
516  // Is it an up or down event?
517  int32_t action = AKeyEvent_getAction(event);
518  if (action == AKEY_EVENT_ACTION_DOWN) {
519  if (AKeyEvent_getRepeatCount(event) > 0) {
520  _input->button_resume_down(button);
521  } else {
522  _input->button_down(button);
523  }
524  } else if (action == AKEY_EVENT_ACTION_UP) {
525  _input->button_up(button);
526  }
527  // TODO AKEY_EVENT_ACTION_MULTIPLE
528 
529  return 1;
530 }
531 
532 /**
533  * Processes a motion event.
534  */
535 int32_t AndroidGraphicsWindow::
536 handle_motion_event(const AInputEvent *event) {
537  int32_t action = AMotionEvent_getAction(event);
538  action &= AMOTION_EVENT_ACTION_MASK;
539 
540  if (action == AMOTION_EVENT_ACTION_DOWN ||
541  action == AMOTION_EVENT_ACTION_UP) {
542  // The up event doesn't let us know which button is up, so we need to
543  // keep track of the button state ourselves.
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;
547  }
548  int32_t changed = _mouse_button_state ^ button_state;
549  if (changed != 0) {
550  if (changed & AMOTION_EVENT_BUTTON_PRIMARY) {
551  if (button_state & AMOTION_EVENT_BUTTON_PRIMARY) {
552  _input->button_down(MouseButton::one());
553  } else {
554  _input->button_up(MouseButton::one());
555  }
556  }
557  if (changed & AMOTION_EVENT_BUTTON_SECONDARY) {
558  if (button_state & AMOTION_EVENT_BUTTON_SECONDARY) {
559  _input->button_down(MouseButton::three());
560  } else {
561  _input->button_up(MouseButton::three());
562  }
563  }
564  _mouse_button_state = button_state;
565  }
566  }
567 
568  float x = AMotionEvent_getX(event, 0) - _app->contentRect.left;
569  float y = AMotionEvent_getY(event, 0) - _app->contentRect.top;
570 
571  _input->set_pointer_in_window(x, y);
572 
573  return 1;
574 }
575 
576 /**
577  * Given an Android keycode, returns an appropriate ButtonHandle object, or
578  * ButtonHandle::none() if a matching ButtonHandle does not exist.
579  */
580 ButtonHandle AndroidGraphicsWindow::
581 map_button(int32_t keycode) {
582  switch (keycode) {
583  case AKEYCODE_SOFT_LEFT:
584  case AKEYCODE_SOFT_RIGHT:
585  case AKEYCODE_HOME:
586  case AKEYCODE_BACK:
587  case AKEYCODE_CALL:
588  case AKEYCODE_ENDCALL:
589  break;
590  case AKEYCODE_0:
591  return KeyboardButton::ascii_key('0');
592  case AKEYCODE_1:
593  return KeyboardButton::ascii_key('1');
594  case AKEYCODE_2:
595  return KeyboardButton::ascii_key('2');
596  case AKEYCODE_3:
597  return KeyboardButton::ascii_key('3');
598  case AKEYCODE_4:
599  return KeyboardButton::ascii_key('4');
600  case AKEYCODE_5:
601  return KeyboardButton::ascii_key('5');
602  case AKEYCODE_6:
603  return KeyboardButton::ascii_key('6');
604  case AKEYCODE_7:
605  return KeyboardButton::ascii_key('7');
606  case AKEYCODE_8:
607  return KeyboardButton::ascii_key('8');
608  case AKEYCODE_9:
609  return KeyboardButton::ascii_key('9');
610  case AKEYCODE_STAR:
611  return KeyboardButton::ascii_key('*');
612  case AKEYCODE_POUND:
613  return KeyboardButton::ascii_key('#');
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:
625  case AKEYCODE_POWER:
626  case AKEYCODE_CAMERA:
627  case AKEYCODE_CLEAR:
628  break;
629  case AKEYCODE_A:
630  return KeyboardButton::ascii_key('a');
631  case AKEYCODE_B:
632  return KeyboardButton::ascii_key('b');
633  case AKEYCODE_C:
634  return KeyboardButton::ascii_key('c');
635  case AKEYCODE_D:
636  return KeyboardButton::ascii_key('d');
637  case AKEYCODE_E:
638  return KeyboardButton::ascii_key('e');
639  case AKEYCODE_F:
640  return KeyboardButton::ascii_key('f');
641  case AKEYCODE_G:
642  return KeyboardButton::ascii_key('g');
643  case AKEYCODE_H:
644  return KeyboardButton::ascii_key('h');
645  case AKEYCODE_I:
646  return KeyboardButton::ascii_key('i');
647  case AKEYCODE_J:
648  return KeyboardButton::ascii_key('j');
649  case AKEYCODE_K:
650  return KeyboardButton::ascii_key('k');
651  case AKEYCODE_L:
652  return KeyboardButton::ascii_key('l');
653  case AKEYCODE_M:
654  return KeyboardButton::ascii_key('m');
655  case AKEYCODE_N:
656  return KeyboardButton::ascii_key('n');
657  case AKEYCODE_O:
658  return KeyboardButton::ascii_key('o');
659  case AKEYCODE_P:
660  return KeyboardButton::ascii_key('p');
661  case AKEYCODE_Q:
662  return KeyboardButton::ascii_key('q');
663  case AKEYCODE_R:
664  return KeyboardButton::ascii_key('r');
665  case AKEYCODE_S:
666  return KeyboardButton::ascii_key('s');
667  case AKEYCODE_T:
668  return KeyboardButton::ascii_key('t');
669  case AKEYCODE_U:
670  return KeyboardButton::ascii_key('u');
671  case AKEYCODE_V:
672  return KeyboardButton::ascii_key('v');
673  case AKEYCODE_W:
674  return KeyboardButton::ascii_key('w');
675  case AKEYCODE_X:
676  return KeyboardButton::ascii_key('x');
677  case AKEYCODE_Y:
678  return KeyboardButton::ascii_key('y');
679  case AKEYCODE_Z:
680  return KeyboardButton::ascii_key('z');
681  case AKEYCODE_COMMA:
682  return KeyboardButton::ascii_key(',');
683  case AKEYCODE_PERIOD:
684  return KeyboardButton::ascii_key('.');
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();
693  case AKEYCODE_TAB:
694  return KeyboardButton::tab();
695  case AKEYCODE_SPACE:
696  return KeyboardButton::space();
697  case AKEYCODE_SYM:
698  case AKEYCODE_EXPLORER:
699  case AKEYCODE_ENVELOPE:
700  break;
701  case AKEYCODE_ENTER:
702  return KeyboardButton::enter();
703  case AKEYCODE_DEL:
704  return KeyboardButton::backspace();
705  case AKEYCODE_GRAVE:
706  return KeyboardButton::ascii_key('`');
707  case AKEYCODE_MINUS:
708  return KeyboardButton::ascii_key('-');
709  case AKEYCODE_EQUALS:
710  return KeyboardButton::ascii_key('=');
711  case AKEYCODE_LEFT_BRACKET:
712  return KeyboardButton::ascii_key('[');
713  case AKEYCODE_RIGHT_BRACKET:
714  return KeyboardButton::ascii_key(']');
715  case AKEYCODE_BACKSLASH:
716  return KeyboardButton::ascii_key('\\');
717  case AKEYCODE_SEMICOLON:
718  return KeyboardButton::ascii_key(';');
719  case AKEYCODE_APOSTROPHE:
720  return KeyboardButton::ascii_key('\'');
721  case AKEYCODE_SLASH:
722  return KeyboardButton::ascii_key('/');
723  case AKEYCODE_AT:
724  return KeyboardButton::ascii_key('@');
725  case AKEYCODE_NUM:
726  case AKEYCODE_HEADSETHOOK:
727  case AKEYCODE_FOCUS:
728  break;
729  case AKEYCODE_PLUS:
730  return KeyboardButton::ascii_key('+');
731  case AKEYCODE_MENU:
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:
741  case AKEYCODE_MUTE:
742  break;
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:
764  break;
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:
782  break;
783  case AKEYCODE_SYSRQ:
784  return KeyboardButton::print_screen();
785  case AKEYCODE_BREAK:
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();
793  case AKEYCODE_F1:
794  return KeyboardButton::f1();
795  case AKEYCODE_F2:
796  return KeyboardButton::f2();
797  case AKEYCODE_F3:
798  return KeyboardButton::f3();
799  case AKEYCODE_F4:
800  return KeyboardButton::f4();
801  case AKEYCODE_F5:
802  return KeyboardButton::f5();
803  case AKEYCODE_F6:
804  return KeyboardButton::f6();
805  case AKEYCODE_F7:
806  return KeyboardButton::f7();
807  case AKEYCODE_F8:
808  return KeyboardButton::f8();
809  case AKEYCODE_F9:
810  return KeyboardButton::f9();
811  case AKEYCODE_F10:
812  return KeyboardButton::f10();
813  case AKEYCODE_F11:
814  return KeyboardButton::f11();
815  case AKEYCODE_F12:
816  return KeyboardButton::f12();
817  case AKEYCODE_NUM_LOCK:
818  return KeyboardButton::num_lock();
819  default:
820  break;
821  }
822  return ButtonHandle::none();
823 }
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
void button_down(ButtonHandle button, double time=ClockObject::get_global_clock() ->get_frame_time())
Records that the indicated button has been depressed.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static ButtonHandle three()
Returns the ButtonHandle associated with the third mouse button.
Definition: mouseButton.cxx:59
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_size
Specifies the requested size of the window, in pixels.
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
set_minimized
Specifies whether the window should be created minimized (true), or normal (false).
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_pointer_in_window(double x, double y, double time=ClockObject::get_global_clock() ->get_frame_time())
To be called by a particular kind of GraphicsWindow to indicate that the pointer is within the window...
static ButtonHandle one()
Returns the ButtonHandle associated with the first mouse button.
Definition: mouseButton.cxx:43
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...
Definition: pStatTimer.h:30
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:26
has_fullscreen
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...
set_origin
Specifies the origin on the screen (in pixels, relative to the top-left corner) at which the window s...
const std::string get_egl_error_string(int error)
Returns the given EGL error as string.
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.
Definition: graphicsPipe.h:52
void button_up(ButtonHandle button, double time=ClockObject::get_global_clock() ->get_frame_time())
Records that the indicated button has been released.
This is a virtual input device that represents the keyboard and mouse pair that is associated with a ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a base class for the various different classes that represent the result of a frame of render...
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).
clear_fullscreen
Removes the fullscreen specification from the properties.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A thread; that is, a lightweight process.
Definition: thread.h:46
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void button_resume_down(ButtonHandle button, double time=ClockObject::get_global_clock() ->get_frame_time())
Records that the indicated button was depressed earlier, and we only just detected the event after th...
void destroy_context()
Destroys the context previously created by create_context.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
get_fullscreen
Returns true if the window is in fullscreen mode.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
static ButtonHandle ascii_key(char ascii_equivalent)
Returns the ButtonHandle associated with the particular ASCII character, if there is one,...
set_open
Specifies whether the window should be open.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_foreground
Specifies whether the window should be opened in the foreground (true), or left in the background (fa...
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.