Panda3D
androidGraphicsWindow.cxx
1 // Filename: androidGraphicsWindow.cxx
2 // Created by: rdb (11Jan13)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "androidGraphicsWindow.h"
16 #include "androidGraphicsStateGuardian.h"
17 #include "config_androiddisplay.h"
18 #include "androidGraphicsPipe.h"
19 
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"
28 
29 #include "android_native_app_glue.h"
30 #include <android/window.h>
31 #include <android/log.h>
32 
33 extern struct android_app* panda_android_app;
34 
35 TypeHandle AndroidGraphicsWindow::_type_handle;
36 
37 ////////////////////////////////////////////////////////////////////
38 // Function: AndroidGraphicsWindow::Constructor
39 // Access: Public
40 // Description:
41 ////////////////////////////////////////////////////////////////////
42 AndroidGraphicsWindow::
43 AndroidGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
44  const string &name,
45  const FrameBufferProperties &fb_prop,
46  const WindowProperties &win_prop,
47  int flags,
49  GraphicsOutput *host) :
50  GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
51 {
52  AndroidGraphicsPipe *android_pipe;
53  DCAST_INTO_V(android_pipe, _pipe);
54 
55  _egl_display = android_pipe->_egl_display;
56  _egl_surface = 0;
57 
58  _app = panda_android_app;
59 
62  add_input_device(device);
63 }
64 
65 ////////////////////////////////////////////////////////////////////
66 // Function: AndroidGraphicsWindow::Destructor
67 // Access: Public, Virtual
68 // Description:
69 ////////////////////////////////////////////////////////////////////
70 AndroidGraphicsWindow::
71 ~AndroidGraphicsWindow() {
72  destroy_surface();
73 }
74 
75 ////////////////////////////////////////////////////////////////////
76 // Function: AndroidGraphicsWindow::begin_frame
77 // Access: Public, Virtual
78 // Description: This function will be called within the draw thread
79 // before beginning rendering for a given frame. It
80 // should do whatever setup is required, and return true
81 // if the frame should be rendered, or false if it
82 // should be skipped.
83 ////////////////////////////////////////////////////////////////////
85 begin_frame(FrameMode mode, Thread *current_thread) {
86  PStatTimer timer(_make_current_pcollector, current_thread);
87 
88  begin_frame_spam(mode);
89  if (_gsg == (GraphicsStateGuardian *)NULL) {
90  return false;
91  }
92 
93  //XXX not open yet.
94  if (_egl_surface == EGL_NO_SURFACE) {
95  return false;
96  }
97 
98  AndroidGraphicsStateGuardian *androidgsg;
99  DCAST_INTO_R(androidgsg, _gsg, false);
100  {
101  if (eglGetCurrentDisplay() == _egl_display &&
102  eglGetCurrentSurface(EGL_READ) == _egl_surface &&
103  eglGetCurrentSurface(EGL_DRAW) == _egl_surface &&
104  eglGetCurrentContext() == androidgsg->_context) {
105  // No need to make the context current again. Short-circuit
106  // this possibly-expensive call.
107  } else {
108  // Need to set the 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";
112  }
113  }
114  }
115 
116  // Now that we have made the context current to a window, we can
117  // reset the GSG state if this is the first time it has been used.
118  // (We can't just call reset() when we construct the GSG, because
119  // reset() requires having a current context.)
120  androidgsg->reset_if_new();
121 
122  if (mode == FM_render) {
123  // begin_render_texture();
124  clear_cube_map_selection();
125  }
126 
127  _gsg->set_current_properties(&get_fb_properties());
128  return _gsg->begin_frame(current_thread);
129 }
130 
131 ////////////////////////////////////////////////////////////////////
132 // Function: AndroidGraphicsWindow::end_frame
133 // Access: Public, Virtual
134 // Description: This function will be called within the draw thread
135 // after rendering is completed for a given frame. It
136 // should do whatever finalization is required.
137 ////////////////////////////////////////////////////////////////////
139 end_frame(FrameMode mode, Thread *current_thread) {
140  end_frame_spam(mode);
141  nassertv(_gsg != (GraphicsStateGuardian *)NULL);
142 
143  if (mode == FM_render) {
144  // end_render_texture();
145  copy_to_textures();
146  }
147 
148  _gsg->end_frame(current_thread);
149 
150  if (mode == FM_render) {
151  trigger_flip();
152  clear_cube_map_selection();
153  }
154 }
155 
156 ////////////////////////////////////////////////////////////////////
157 // Function: AndroidGraphicsWindow::end_flip
158 // Access: Public, Virtual
159 // Description: This function will be called within the draw thread
160 // after begin_flip() has been called on all windows, to
161 // finish the exchange of the front and back buffers.
162 //
163 // This should cause the window to wait for the flip, if
164 // necessary.
165 ////////////////////////////////////////////////////////////////////
168  if (_gsg != (GraphicsStateGuardian *)NULL && _flip_ready) {
169 
170  // It doesn't appear to be necessary to ensure the graphics
171  // context is current before flipping the windows, and insisting
172  // on doing so can be a significant performance hit.
173 
174  //make_current();
175 
176  if (_egl_surface != EGL_NO_SURFACE) {
177  eglSwapBuffers(_egl_display, _egl_surface);
178  }
179  }
181 }
182 
183 ////////////////////////////////////////////////////////////////////
184 // Function: AndroidGraphicsWindow::process_events
185 // Access: Public, Virtual
186 // Description: Do whatever processing is necessary to ensure that
187 // the window responds to user events. Also, honor any
188 // requests recently made via request_properties()
189 //
190 // This function is called only within the window
191 // thread.
192 ////////////////////////////////////////////////////////////////////
196 
197  // Read all pending events.
198  int looper_id;
199  int events;
200  struct android_poll_source* source;
201 
202  // Loop until all events are read.
203  while ((looper_id = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0) {
204  // Process this event.
205  if (source != NULL) {
206  source->process(_app, source);
207  }
208  }
209 }
210 
211 ////////////////////////////////////////////////////////////////////
212 // Function: AndroidGraphicsWindow::set_properties_now
213 // Access: Public, Virtual
214 // Description: Applies the requested set of properties to the
215 // window, if possible, for instance to request a change
216 // in size or minimization status.
217 //
218 // The window properties are applied immediately, rather
219 // than waiting until the next frame. This implies that
220 // this method may *only* be called from within the
221 // window thread.
222 //
223 // The return value is true if the properties are set,
224 // false if they are ignored. This is mainly useful for
225 // derived classes to implement extensions to this
226 // function.
227 ////////////////////////////////////////////////////////////////////
230  if (_pipe == (GraphicsPipe *)NULL) {
231  // If the pipe is null, we're probably closing down.
233  return;
234  }
235 
237  if (!properties.is_any_specified()) {
238  // The base class has already handled this case.
239  return;
240  }
241 
242  // There's not really much we can change on Android.
243  if (properties.has_fullscreen()) {
244  uint32_t add_flags = 0;
245  uint32_t del_flags = 0;
246  if (_properties.get_fullscreen()) {
247  add_flags |= AWINDOW_FLAG_FULLSCREEN;
248  } else {
249  del_flags |= AWINDOW_FLAG_FULLSCREEN;
250  }
251  ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
252 
253  _properties.set_fullscreen(properties.get_fullscreen());
254  properties.clear_fullscreen();
255  }
256 }
257 
258 ////////////////////////////////////////////////////////////////////
259 // Function: AndroidGraphicsWindow::close_window
260 // Access: Protected, Virtual
261 // Description: Closes the window right now. Called from the window
262 // thread.
263 ////////////////////////////////////////////////////////////////////
264 void AndroidGraphicsWindow::
265 close_window() {
266  destroy_surface();
267 
268  if (_gsg != (GraphicsStateGuardian *)NULL) {
269  _gsg.clear();
270  }
271 
272  GraphicsWindow::close_window();
273 }
274 
275 ////////////////////////////////////////////////////////////////////
276 // Function: AndroidGraphicsWindow::open_window
277 // Access: Protected, Virtual
278 // Description: Opens the window right now. Called from the window
279 // thread. Returns true if the window is successfully
280 // opened, or false if there was a problem.
281 ////////////////////////////////////////////////////////////////////
282 bool AndroidGraphicsWindow::
283 open_window() {
284  // GSG Creation/Initialization
285  AndroidGraphicsStateGuardian *androidgsg;
286  if (_gsg == 0) {
287  // There is no old gsg. Create a new one.
288  androidgsg = new AndroidGraphicsStateGuardian(_engine, _pipe, NULL);
289  androidgsg->choose_pixel_format(_fb_properties, false, false);
290  _gsg = androidgsg;
291  } else {
292  // If the old gsg has the wrong pixel format, create a
293  // new one that shares with the old gsg.
294  DCAST_INTO_R(androidgsg, _gsg, false);
295  if (!androidgsg->get_fb_properties().subsumes(_fb_properties)) {
296  androidgsg = new AndroidGraphicsStateGuardian(_engine, _pipe, androidgsg);
297  androidgsg->choose_pixel_format(_fb_properties, false, false);
298  _gsg = androidgsg;
299  }
300  }
301 
302  // Register the callbacks
303  assert(_app != NULL);
304  _app->userData = this;
305  _app->onAppCmd = handle_command;
306  _app->onInputEvent = handle_input_event;
307 
308  // Wait until Android has opened the window.
309  while (_app->window == NULL) {
310  process_events();
311  }
312 
313  // create_surface should have been called by now.
314  if (_egl_surface == EGL_NO_SURFACE) {
315  return false;
316  }
317 
318  // Set some other properties.
319  _properties.set_origin(0, 0);
320  _properties.set_cursor_hidden(true);
321  _properties.set_undecorated(true);
322 
324  (_fb_properties, androidgsg->get_gl_renderer())) {
325  close_window();
326  return false;
327  }
328 
329  _fb_properties = androidgsg->get_fb_properties();
330 
331  androiddisplay_cat.error() << "open_window done\n";
332 
333  return true;
334 }
335 
336 ////////////////////////////////////////////////////////////////////
337 // Function: AndroidGraphicsWindow::destroy_surface
338 // Access: Protected, Virtual
339 // Description: Terminates the EGL surface.
340 ////////////////////////////////////////////////////////////////////
341 void AndroidGraphicsWindow::
342 destroy_surface() {
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";
347  }
348  _egl_surface = EGL_NO_SURFACE;
349  }
350 
351  // Destroy the current context.
352  if (_gsg != (GraphicsStateGuardian *)NULL) {
353  AndroidGraphicsStateGuardian *androidgsg;
354  DCAST_INTO_V(androidgsg, _gsg);
355  androidgsg->destroy_context();
356  }
357 }
358 
359 ////////////////////////////////////////////////////////////////////
360 // Function: AndroidGraphicsWindow::create_surface
361 // Access: Protected, Virtual
362 // Description: Creates the EGL surface.
363 ////////////////////////////////////////////////////////////////////
364 bool AndroidGraphicsWindow::
365 create_surface() {
366  AndroidGraphicsStateGuardian *androidgsg;
367  DCAST_INTO_R(androidgsg, _gsg, false);
368 
369  // Reconfigure the window buffers to match that of our framebuffer config.
370  ANativeWindow_setBuffersGeometry(_app->window, 0, 0, androidgsg->_format);
371 
372  // Set any window flags
373  uint32_t add_flags = 0;
374  uint32_t del_flags = 0;
375  if (_properties.get_fullscreen()) {
376  add_flags |= AWINDOW_FLAG_FULLSCREEN;
377  } else {
378  del_flags |= AWINDOW_FLAG_FULLSCREEN;
379  }
380  ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
381 
382  // Create the EGL surface.
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";
387  return false;
388  }
389 
390  // Create a context.
391  if (androidgsg->_context == EGL_NO_CONTEXT) {
392  androiddisplay_cat.error() << "creating context\n";
393  if (!androidgsg->create_context()) {
394  return false;
395  }
396  }
397 
398  // Switch to our newly created context.
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";
402  }
403 
404  // Query the size of the surface.
405  //EGLint width, height;
406  //eglQuerySurface(_egl_display, _egl_surface, EGL_WIDTH, &width);
407  //eglQuerySurface(_egl_display, _egl_surface, EGL_HEIGHT, &height);
408 
409  androidgsg->reset_if_new();
410  if (!androidgsg->is_valid()) {
411  close_window();
412  return false;
413  }
414 
415  return true;
416 }
417 
418 ////////////////////////////////////////////////////////////////////
419 // Function: AndroidGraphicsWindow::handle_command
420 // Access: Private, Static
421 // Description: Android app sends a command from the main thread.
422 ////////////////////////////////////////////////////////////////////
423 void AndroidGraphicsWindow::
424 handle_command(struct android_app *app, int32_t command) {
425  AndroidGraphicsWindow* window = (AndroidGraphicsWindow*) app->userData;
426  window->ns_handle_command(command);
427 }
428 
429 ////////////////////////////////////////////////////////////////////
430 // Function: AndroidGraphicsWindow::ns_handle_command
431 // Access: Private
432 // Description: Android app sends a command from the main thread.
433 ////////////////////////////////////////////////////////////////////
434 void AndroidGraphicsWindow::
435 ns_handle_command(int32_t command) {
436  WindowProperties properties;
437 
438  switch (command) {
439  case APP_CMD_SAVE_STATE:
440  // The system has asked us to save our current state. Do so.
441  //engine->app->savedState = malloc(sizeof(struct saved_state));
442  //*((struct saved_state*)engine->app->savedState) = engine->state;
443  //engine->app->savedStateSize = sizeof(struct saved_state);
444  break;
445  case APP_CMD_INIT_WINDOW:
446  // The window is being shown, get it ready.
447  if (_app->window != NULL) {
448  create_surface();
449  properties.set_size(ANativeWindow_getWidth(_app->window),
450  ANativeWindow_getHeight(_app->window));
451  properties.set_minimized(false);
452  system_changed_properties(properties);
453  }
454  break;
455  case APP_CMD_CONFIG_CHANGED:
456  properties.set_size(ANativeWindow_getWidth(_app->window),
457  ANativeWindow_getHeight(_app->window));
458  system_changed_properties(properties);
459  break;
460  case APP_CMD_TERM_WINDOW:
461  destroy_surface();
462  properties.set_minimized(true);
463  system_changed_properties(properties);
464  break;
465  case APP_CMD_WINDOW_RESIZED:
466  properties.set_size(ANativeWindow_getWidth(_app->window),
467  ANativeWindow_getHeight(_app->window));
468  break;
469  case APP_CMD_WINDOW_REDRAW_NEEDED:
470  break;
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);
476  break;
477  case APP_CMD_GAINED_FOCUS:
478  properties.set_foreground(true);
479  system_changed_properties(properties);
480  break;
481  case APP_CMD_LOST_FOCUS:
482  properties.set_foreground(false);
483  system_changed_properties(properties);
484  break;
485  case APP_CMD_DESTROY:
486  close_window();
487  properties.set_open(false);
488  system_changed_properties(properties);
489  break;
490  }
491 }
492 
493 ////////////////////////////////////////////////////////////////////
494 // Function: AndroidGraphicsWindow::handle_input_event
495 // Access: Private, Static
496 // Description: Processes an input event. Returns 1 if the event
497 // was handled, 0 otherwise.
498 ////////////////////////////////////////////////////////////////////
499 int32_t AndroidGraphicsWindow::
500 handle_input_event(struct android_app* app, AInputEvent *event) {
501  AndroidGraphicsWindow* window = (AndroidGraphicsWindow*) app->userData;
502 
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);
509  }
510  return 0;
511 }
512 
513 ////////////////////////////////////////////////////////////////////
514 // Function: AndroidGraphicsWindow::handle_keystroke
515 // Access: Private
516 // Description: Processes a key event.
517 ////////////////////////////////////////////////////////////////////
518 int32_t AndroidGraphicsWindow::
519 handle_key_event(const AInputEvent *event) {
520  /*
521  int32_t meta = AKeyEvent_getMetaState(event);
522  if (meta | AMETA_ALT_ON) {
523  _input_devices[0].button_down(KeyboardButton.alt());
524  }
525  if (meta | AMETA_ALT_LEFT_ON) {
526  _input_devices[0].button_down(KeyboardButton.lalt());
527  }
528  if (meta | AMETA_ALT_RIGHT_ON) {
529  _input_devices[0].button_down(KeyboardButton.ralt());
530  }
531  if (meta | AMETA_SHIFT_ON) {
532  _input_devices[0].button_down(KeyboardButton.shift());
533  }
534  if (meta | AMETA_SHIFT_LEFT_ON) {
535  _input_devices[0].button_down(KeyboardButton.lshift());
536  }
537  if (meta | AMETA_SHIFT_RIGHT_ON) {
538  _input_devices[0].button_down(KeyboardButton.rshift());
539  }*/
540 
541  int32_t keycode = AKeyEvent_getKeyCode(event);
542  ButtonHandle button = map_button(keycode);
543 
544  if (button == ButtonHandle::none()) {
545  androiddisplay_cat.warning()
546  << "Unknown keycode: " << keycode << "\n";
547  return 0;
548  }
549 
550  // Is it an up or down event?
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);
556  }
557  //TODO getRepeatCount, ACTION_MULTIPLE
558 
559  return 1;
560 }
561 
562 ////////////////////////////////////////////////////////////////////
563 // Function: AndroidGraphicsWindow::handle_motion_event
564 // Access: Private
565 // Description: Processes a motion event.
566 ////////////////////////////////////////////////////////////////////
567 int32_t AndroidGraphicsWindow::
568 handle_motion_event(const AInputEvent *event) {
569  int32_t action = AMotionEvent_getAction(event);
570  action &= AMOTION_EVENT_ACTION_MASK;
571 
572  if (action == AMOTION_EVENT_ACTION_DOWN) {
573  _input_devices[0].button_down(MouseButton::one());
574  } else if (action == AMOTION_EVENT_ACTION_UP) {
575  _input_devices[0].button_up(MouseButton::one());
576  }
577 
578  float x = AMotionEvent_getX(event, 0) - _app->contentRect.left;
579  float y = AMotionEvent_getY(event, 0) - _app->contentRect.top;
580 
581  _input_devices[0].set_pointer_in_window(x, y);
582 
583  return 1;
584 }
585 
586 ////////////////////////////////////////////////////////////////////
587 // Function: AndroidGraphicsWindow::map_button
588 // Access: Private
589 // Description: Given an Android keycode, returns an appropriate
590 // ButtonHandle object, or ButtonHandle::none() if
591 // a matching ButtonHandle does not exist.
592 ////////////////////////////////////////////////////////////////////
593 ButtonHandle AndroidGraphicsWindow::
594 map_button(int32_t keycode) {
595  switch (keycode) {
596  case AKEYCODE_SOFT_LEFT:
597  case AKEYCODE_SOFT_RIGHT:
598  case AKEYCODE_HOME:
599  case AKEYCODE_BACK:
600  case AKEYCODE_CALL:
601  case AKEYCODE_ENDCALL:
602  break;
603  case AKEYCODE_0:
604  return KeyboardButton::ascii_key('0');
605  case AKEYCODE_1:
606  return KeyboardButton::ascii_key('1');
607  case AKEYCODE_2:
608  return KeyboardButton::ascii_key('2');
609  case AKEYCODE_3:
610  return KeyboardButton::ascii_key('3');
611  case AKEYCODE_4:
612  return KeyboardButton::ascii_key('4');
613  case AKEYCODE_5:
614  return KeyboardButton::ascii_key('5');
615  case AKEYCODE_6:
616  return KeyboardButton::ascii_key('6');
617  case AKEYCODE_7:
618  return KeyboardButton::ascii_key('7');
619  case AKEYCODE_8:
620  return KeyboardButton::ascii_key('8');
621  case AKEYCODE_9:
622  return KeyboardButton::ascii_key('9');
623  case AKEYCODE_STAR:
624  return KeyboardButton::ascii_key('*');
625  case AKEYCODE_POUND:
626  return KeyboardButton::ascii_key('#');
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:
638  case AKEYCODE_POWER:
639  case AKEYCODE_CAMERA:
640  case AKEYCODE_CLEAR:
641  break;
642  case AKEYCODE_A:
643  return KeyboardButton::ascii_key('a');
644  case AKEYCODE_B:
645  return KeyboardButton::ascii_key('b');
646  case AKEYCODE_C:
647  return KeyboardButton::ascii_key('c');
648  case AKEYCODE_D:
649  return KeyboardButton::ascii_key('d');
650  case AKEYCODE_E:
651  return KeyboardButton::ascii_key('e');
652  case AKEYCODE_F:
653  return KeyboardButton::ascii_key('f');
654  case AKEYCODE_G:
655  return KeyboardButton::ascii_key('g');
656  case AKEYCODE_H:
657  return KeyboardButton::ascii_key('h');
658  case AKEYCODE_I:
659  return KeyboardButton::ascii_key('i');
660  case AKEYCODE_J:
661  return KeyboardButton::ascii_key('j');
662  case AKEYCODE_K:
663  return KeyboardButton::ascii_key('k');
664  case AKEYCODE_L:
665  return KeyboardButton::ascii_key('l');
666  case AKEYCODE_M:
667  return KeyboardButton::ascii_key('m');
668  case AKEYCODE_N:
669  return KeyboardButton::ascii_key('n');
670  case AKEYCODE_O:
671  return KeyboardButton::ascii_key('o');
672  case AKEYCODE_P:
673  return KeyboardButton::ascii_key('p');
674  case AKEYCODE_Q:
675  return KeyboardButton::ascii_key('q');
676  case AKEYCODE_R:
677  return KeyboardButton::ascii_key('r');
678  case AKEYCODE_S:
679  return KeyboardButton::ascii_key('s');
680  case AKEYCODE_T:
681  return KeyboardButton::ascii_key('t');
682  case AKEYCODE_U:
683  return KeyboardButton::ascii_key('u');
684  case AKEYCODE_V:
685  return KeyboardButton::ascii_key('v');
686  case AKEYCODE_W:
687  return KeyboardButton::ascii_key('w');
688  case AKEYCODE_X:
689  return KeyboardButton::ascii_key('x');
690  case AKEYCODE_Y:
691  return KeyboardButton::ascii_key('y');
692  case AKEYCODE_Z:
693  return KeyboardButton::ascii_key('z');
694  case AKEYCODE_COMMA:
695  return KeyboardButton::ascii_key(',');
696  case AKEYCODE_PERIOD:
697  return KeyboardButton::ascii_key('.');
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();
706  case AKEYCODE_TAB:
707  return KeyboardButton::tab();
708  case AKEYCODE_SPACE:
709  return KeyboardButton::space();
710  case AKEYCODE_SYM:
711  case AKEYCODE_EXPLORER:
712  case AKEYCODE_ENVELOPE:
713  break;
714  case AKEYCODE_ENTER:
715  return KeyboardButton::enter();
716  case AKEYCODE_DEL:
717  return KeyboardButton::del();
718  case AKEYCODE_GRAVE:
719  return KeyboardButton::ascii_key('`');
720  case AKEYCODE_MINUS:
721  return KeyboardButton::ascii_key('-');
722  case AKEYCODE_EQUALS:
723  return KeyboardButton::ascii_key('=');
724  case AKEYCODE_LEFT_BRACKET:
725  return KeyboardButton::ascii_key('[');
726  case AKEYCODE_RIGHT_BRACKET:
727  return KeyboardButton::ascii_key(']');
728  case AKEYCODE_BACKSLASH:
729  return KeyboardButton::ascii_key('\\');
730  case AKEYCODE_SEMICOLON:
731  return KeyboardButton::ascii_key(';');
732  case AKEYCODE_APOSTROPHE:
733  return KeyboardButton::ascii_key('\'');
734  case AKEYCODE_SLASH:
735  return KeyboardButton::ascii_key('/');
736  case AKEYCODE_AT:
737  return KeyboardButton::ascii_key('@');
738  case AKEYCODE_NUM:
739  case AKEYCODE_HEADSETHOOK:
740  case AKEYCODE_FOCUS:
741  break;
742  case AKEYCODE_PLUS:
743  return KeyboardButton::ascii_key('+');
744  case AKEYCODE_MENU:
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:
753  case AKEYCODE_MUTE:
754  break;
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:
776  default:
777  break;
778  }
779  return ButtonHandle::none();
780 }
static GraphicsWindowInputDevice pointer_and_keyboard(GraphicsWindow *host, const string &name)
This named constructor returns an input device that has both a keyboard and pointer.
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.
static ButtonHandle none()
Returns a special zero-valued ButtonHandle that is used to indicate no button.
Definition: buttonHandle.I:205
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.
static ButtonHandle one()
Returns the ButtonHandle associated with the first mouse button.
Definition: mouseButton.cxx:50
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...
Definition: pStatTimer.h:34
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:28
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.
Definition: graphicsPipe.h:58
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 structure representing a single input device that may be associated with a window...
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.
Definition: thread.h:51
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.
Definition: typeHandle.h:85
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...
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.