Panda3D
 All Classes Functions Variables Enumerations
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.
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
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
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
bool get_fullscreen() const
Returns true if the window is in fullscreen mode.
An interface to manage Android windows and their appropriate EGL surfaces.
bool verify_hardware_software(const FrameBufferProperties &props, const string &renderer) const
Validates that the properties represent the desired kind of renderer (hardware or software)...
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
A container for the various kinds of properties we might ask to have on a graphics window before we o...
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
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
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...
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
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.
This class is the main interface to controlling the render process.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
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.
bool has_fullscreen() const
Returns true if set_fullscreen() has been specified.