Android support, part 2 (display module)

This commit is contained in:
rdb 2013-01-24 18:19:54 +00:00
parent c26c0e6a97
commit 0631441b20
14 changed files with 1901 additions and 5 deletions

View File

@ -9,7 +9,7 @@
#define BUILD_DIRECTORY $[HAVE_GLES]
#define COMPONENT_LIBS \
p3glesgsg p3egldisplay
p3glesgsg p3egldisplay p3androiddisplay
#define LOCAL_LIBS p3gsgbase p3display p3express
#define OTHER_LIBS p3interrogatedb:c p3dconfig:c p3dtoolconfig:m \

View File

@ -1,5 +1,5 @@
// Filename: pandagles.cxx
// Created by: pro-rsoft (8Jun09)
// Created by: rdb (8Jun09)
//
////////////////////////////////////////////////////////////////////
@ -8,7 +8,10 @@
#define OPENGLES_1
#include "config_glesgsg.h"
#ifdef HAVE_EGL
#if defined(ANDROID)
#include "config_androiddisplay.h"
#include "androidGraphicsPipe.h"
#elif defined(HAVE_EGL)
#include "config_egldisplay.h"
#include "eglGraphicsPipe.h"
#endif
@ -31,7 +34,9 @@ void
init_libpandagles() {
init_libglesgsg();
#ifdef HAVE_EGL
#if defined(ANDROID)
init_libandroiddisplay();
#elif defined(HAVE_EGL)
init_libegldisplay();
#endif
}
@ -43,7 +48,9 @@ init_libpandagles() {
////////////////////////////////////////////////////////////////////
int
get_pipe_type_pandagles() {
#ifdef HAVE_EGL
#if defined(ANDROID)
return AndroidGraphicsPipe::get_class_type().get_index();
#elif defined(HAVE_EGL)
return eglGraphicsPipe::get_class_type().get_index();
#endif

View File

@ -0,0 +1,14 @@
// Filename: androidGraphicsPipe.I
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,233 @@
// Filename: androidGraphicsPipe.cxx
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
//#include "androidGraphicsBuffer.h"
#include "androidGraphicsPipe.h"
//#include "androidGraphicsPixmap.h"
#include "androidGraphicsWindow.h"
#include "androidGraphicsStateGuardian.h"
#include "config_androiddisplay.h"
#include "frameBufferProperties.h"
TypeHandle AndroidGraphicsPipe::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsPipe::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
AndroidGraphicsPipe::
AndroidGraphicsPipe() {
_is_valid = false;
_supported_types = OT_window | OT_buffer | OT_texture_buffer;
_egl_display = NULL;
_display_width = 0;
_display_height = 0;
_egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (!eglInitialize(_egl_display, NULL, NULL)) {
androiddisplay_cat.error()
<< "Couldn't initialize the EGL display: "
<< get_egl_error_string(eglGetError()) << "\n";
}
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
androiddisplay_cat.error()
<< "Couldn't bind EGL to the OpenGL ES API: "
<< get_egl_error_string(eglGetError()) << "\n";
}
_is_valid = true;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsPipe::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
AndroidGraphicsPipe::
~AndroidGraphicsPipe() {
if (_egl_display) {
if (!eglTerminate(_egl_display)) {
androiddisplay_cat.error() << "Failed to terminate EGL display: "
<< get_egl_error_string(eglGetError()) << "\n";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsPipe::get_interface_name
// Access: Published, Virtual
// Description: Returns the name of the rendering interface
// associated with this GraphicsPipe. This is used to
// present to the user to allow him/her to choose
// between several possible GraphicsPipes available on a
// particular platform, so the name should be meaningful
// and unique for a given platform.
////////////////////////////////////////////////////////////////////
string AndroidGraphicsPipe::
get_interface_name() const {
return "OpenGL ES";
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsPipe::pipe_constructor
// Access: Public, Static
// Description: This function is passed to the GraphicsPipeSelection
// object to allow the user to make a default
// AndroidGraphicsPipe.
////////////////////////////////////////////////////////////////////
PT(GraphicsPipe) AndroidGraphicsPipe::
pipe_constructor() {
return new AndroidGraphicsPipe;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsPipe::get_preferred_window_thread
// Access: Public, Virtual
// Description: Returns an indication of the thread in which this
// GraphicsPipe requires its window processing to be
// performed: typically either the app thread (e.g. X)
// or the draw thread (Windows).
////////////////////////////////////////////////////////////////////
GraphicsPipe::PreferredWindowThread
AndroidGraphicsPipe::get_preferred_window_thread() const {
// Most of the Android NDK window functions can be
// called from any thread. Since we're creating the
// context at open_window time, let's choose "draw".
return PWT_app;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsPipe::make_output
// Access: Protected, Virtual
// Description: Creates a new window on the pipe, if possible.
////////////////////////////////////////////////////////////////////
PT(GraphicsOutput) AndroidGraphicsPipe::
make_output(const string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsEngine *engine,
GraphicsStateGuardian *gsg,
GraphicsOutput *host,
int retry,
bool &precertify) {
if (!_is_valid) {
return NULL;
}
AndroidGraphicsStateGuardian *androidgsg = 0;
if (gsg != 0) {
DCAST_INTO_R(androidgsg, gsg, NULL);
}
// First thing to try: an eglGraphicsWindow
if (retry == 0) {
if (((flags&BF_require_parasite)!=0)||
((flags&BF_refuse_window)!=0)||
((flags&BF_resizeable)!=0)||
((flags&BF_size_track_host)!=0)||
((flags&BF_rtt_cumulative)!=0)||
((flags&BF_can_bind_color)!=0)||
((flags&BF_can_bind_every)!=0)) {
return NULL;
}
return new AndroidGraphicsWindow(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
// Second thing to try: a GLES(2)GraphicsBuffer
/*if (retry == 1) {
if ((host==0)||
// (!gl_support_fbo)||
((flags&BF_require_parasite)!=0)||
((flags&BF_require_window)!=0)) {
return NULL;
}
// Early failure - if we are sure that this buffer WONT
// meet specs, we can bail out early.
if ((flags & BF_fb_props_optional)==0) {
if ((fb_prop.get_indexed_color() > 0)||
(fb_prop.get_back_buffers() > 0)||
(fb_prop.get_accum_bits() > 0)||
(fb_prop.get_multisamples() > 0)) {
return NULL;
}
}
// Early success - if we are sure that this buffer WILL
// meet specs, we can precertify it.
if ((eglgsg != 0) &&
(eglgsg->is_valid()) &&
(!eglgsg->needs_reset()) &&
(eglgsg->_supports_framebuffer_object) &&
(eglgsg->_glDrawBuffers != 0)&&
(fb_prop.is_basic())) {
precertify = true;
}
#ifdef OPENGLES_2
return new GLES2GraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
#else
return new GLESGraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
#endif
}
// Third thing to try: a eglGraphicsBuffer
if (retry == 2) {
if (((flags&BF_require_parasite)!=0)||
((flags&BF_require_window)!=0)||
((flags&BF_resizeable)!=0)||
((flags&BF_size_track_host)!=0)) {
return NULL;
}
if (!support_rtt) {
if (((flags&BF_rtt_cumulative)!=0)||
((flags&BF_can_bind_every)!=0)) {
// If we require Render-to-Texture, but can't be sure we
// support it, bail.
return NULL;
}
}
return new eglGraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
// Fourth thing to try: an eglGraphicsPixmap.
if (retry == 3) {
if (((flags&BF_require_parasite)!=0)||
((flags&BF_require_window)!=0)||
((flags&BF_resizeable)!=0)||
((flags&BF_size_track_host)!=0)) {
return NULL;
}
if (((flags&BF_rtt_cumulative)!=0)||
((flags&BF_can_bind_every)!=0)) {
return NULL;
}
return new eglGraphicsPixmap(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}*/
// Nothing else left to try.
return NULL;
}

View File

@ -0,0 +1,94 @@
// Filename: androidGraphicsPipe.h
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef ANDROIDGRAPHICSPIPE_H
#define ANDROIDGRAPHICSPIPE_H
#include "pandabase.h"
#include "graphicsWindow.h"
#include "graphicsPipe.h"
#ifdef OPENGLES_2
#include "gles2gsg.h"
// #define NativeDisplayType EGLNativeDisplayType
// #define NativePixmapType EGLNativePixmapType
// #define NativeWindowType EGLNativeWindowType
#else
#include "glesgsg.h"
#endif
#include <EGL/egl.h>
class FrameBufferProperties;
class AndroidGraphicsBuffer;
class AndroidGraphicsPixmap;
class AndroidGraphicsWindow;
////////////////////////////////////////////////////////////////////
// Class : AndroidGraphicsPipe
// Description : This graphics pipe represents the interface for
// creating OpenGL ES graphics windows on an X-based
// (e.g. Unix) client.
////////////////////////////////////////////////////////////////////
class AndroidGraphicsPipe : public GraphicsPipe {
public:
AndroidGraphicsPipe();
virtual ~AndroidGraphicsPipe();
virtual string get_interface_name() const;
static PT(GraphicsPipe) pipe_constructor();
public:
virtual PreferredWindowThread get_preferred_window_thread() const;
protected:
virtual PT(GraphicsOutput) make_output(const string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsEngine *engine,
GraphicsStateGuardian *gsg,
GraphicsOutput *host,
int retry,
bool &precertify);
private:
EGLDisplay _egl_display;
GraphicsWindow *_window;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
GraphicsPipe::init_type();
register_type(_type_handle, "AndroidGraphicsPipe",
GraphicsPipe::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class AndroidGraphicsBuffer;
friend class AndroidGraphicsPixmap;
friend class AndroidGraphicsWindow;
};
#include "androidGraphicsPipe.I"
#endif

View File

@ -0,0 +1,25 @@
// Filename: androidGraphicsStateGuardian.I
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::get_fb_properties
// Access: Private
// Description: Gets the FrameBufferProperties for all windows and
// buffers that use this GSG.
////////////////////////////////////////////////////////////////////
INLINE const FrameBufferProperties &AndroidGraphicsStateGuardian::
get_fb_properties() const {
return _fbprops;
}

View File

@ -0,0 +1,403 @@
// Filename: androidGraphicsStateGuardian.cxx
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "androidGraphicsStateGuardian.h"
#include "config_androiddisplay.h"
#include "lightReMutexHolder.h"
#include <dlfcn.h>
TypeHandle AndroidGraphicsStateGuardian::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
AndroidGraphicsStateGuardian::
AndroidGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
AndroidGraphicsStateGuardian *share_with) :
#ifdef OPENGLES_2
GLES2GraphicsStateGuardian(engine, pipe)
#else
GLESGraphicsStateGuardian(engine, pipe)
#endif
{
_share_context = 0;
_context = 0;
_egl_display = 0;
_fbconfig = 0;
_format = 0;
if (share_with != (AndroidGraphicsStateGuardian *)NULL) {
_prepared_objects = share_with->get_prepared_objects();
_share_context = share_with->_context;
}
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
AndroidGraphicsStateGuardian::
~AndroidGraphicsStateGuardian() {
if (_context != (EGLContext)NULL) {
if (!eglDestroyContext(_egl_display, _context)) {
androiddisplay_cat.error() << "Failed to destroy EGL context: "
<< get_egl_error_string(eglGetError()) << "\n";
}
_context = (EGLContext)NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::get_properties
// Access: Private
// Description: Gets the FrameBufferProperties to match the
// indicated config.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsStateGuardian::
get_properties(FrameBufferProperties &properties,
bool &pbuffer_supported, bool &pixmap_supported,
bool &slow, EGLConfig config) {
properties.clear();
// Now update our framebuffer_mode and bit depth appropriately.
EGLint red_size, green_size, blue_size,
alpha_size,
depth_size, stencil_size, samples, surface_type, caveat;
eglGetConfigAttrib(_egl_display, config, EGL_RED_SIZE, &red_size);
eglGetConfigAttrib(_egl_display, config, EGL_GREEN_SIZE, &green_size);
eglGetConfigAttrib(_egl_display, config, EGL_BLUE_SIZE, &blue_size);
eglGetConfigAttrib(_egl_display, config, EGL_ALPHA_SIZE, &alpha_size);
eglGetConfigAttrib(_egl_display, config, EGL_DEPTH_SIZE, &depth_size);
eglGetConfigAttrib(_egl_display, config, EGL_STENCIL_SIZE, &stencil_size);
eglGetConfigAttrib(_egl_display, config, EGL_SAMPLES, &samples);
eglGetConfigAttrib(_egl_display, config, EGL_SURFACE_TYPE, &surface_type);
eglGetConfigAttrib(_egl_display, config, EGL_CONFIG_CAVEAT, &caveat);
int err = eglGetError();
if (err != EGL_SUCCESS) {
androiddisplay_cat.error() << "Failed to get EGL config attrib: "
<< get_egl_error_string(err) << "\n";
}
pbuffer_supported = false;
if ((surface_type & EGL_PBUFFER_BIT)!=0) {
pbuffer_supported = true;
}
pixmap_supported = false;
if ((surface_type & EGL_PIXMAP_BIT)!=0) {
pixmap_supported = true;
}
slow = false;
if (caveat == EGL_SLOW_CONFIG) {
slow = true;
}
if ((surface_type & EGL_WINDOW_BIT)==0) {
// We insist on having a context that will support an onscreen window.
return;
}
properties.set_back_buffers(1);
properties.set_rgb_color(1);
properties.set_color_bits(red_size+green_size+blue_size);
properties.set_stencil_bits(stencil_size);
properties.set_depth_bits(depth_size);
properties.set_alpha_bits(alpha_size);
properties.set_multisamples(samples);
// Set both hardware and software bits, indicating not-yet-known.
properties.set_force_software(1);
properties.set_force_hardware(1);
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::choose_pixel_format
// Access: Private
// Description: Selects a visual or fbconfig for all the windows
// and buffers that use this gsg.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsStateGuardian::
choose_pixel_format(const FrameBufferProperties &properties,
bool need_pbuffer, bool need_pixmap) {
_egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
_fbconfig = 0;
_format = 0;
int attrib_list[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
#ifdef OPENGLES_1
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#endif
#ifdef OPENGLES_2
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#endif
EGL_NONE
};
// First get the number of matching configurations, so we know how much memory to allocate.
int num_configs = 0, returned_configs;
if (!eglChooseConfig(_egl_display, attrib_list, NULL, num_configs, &returned_configs) || returned_configs <= 0) {
androiddisplay_cat.error() << "eglChooseConfig failed: "
<< get_egl_error_string(eglGetError()) << "\n";
return;
}
num_configs = returned_configs;
EGLConfig *configs = new EGLConfig[num_configs];
if (!eglChooseConfig(_egl_display, attrib_list, configs, num_configs, &returned_configs) || returned_configs <= 0) {
androiddisplay_cat.error() << "eglChooseConfig failed: "
<< get_egl_error_string(eglGetError()) << "\n";
delete[] configs;
return;
}
int best_quality = 0;
int best_result = 0;
FrameBufferProperties best_props;
for (int i = 0; i < num_configs; ++i) {
FrameBufferProperties fbprops;
bool pbuffer_supported, pixmap_supported, slow;
get_properties(fbprops, pbuffer_supported, pixmap_supported,
slow, configs[i]);
// We're not protecting this code by an is_debug() check, because if we do,
// some weird compiler bug appears and somehow makes the quality always 0.
const char *pbuffertext = pbuffer_supported ? " (pbuffer)" : "";
const char *pixmaptext = pixmap_supported ? " (pixmap)" : "";
const char *slowtext = slow ? " (slow)" : "";
androiddisplay_cat.debug()
<< i << ": " << fbprops << pbuffertext << pixmaptext << slowtext << "\n";
int quality = fbprops.get_quality(properties);
if ((quality > 0)&&(slow)) quality -= 10000000;
if (need_pbuffer && !pbuffer_supported) {
continue;
}
if (need_pixmap && !pixmap_supported) {
continue;
}
if (quality > best_quality) {
best_quality = quality;
best_result = i;
best_props = fbprops;
}
}
if (best_quality > 0) {
androiddisplay_cat.debug()
<< "Chosen config " << best_result << ": " << best_props << "\n";
_fbconfig = configs[best_result];
eglGetConfigAttrib(_egl_display, _fbconfig, EGL_NATIVE_VISUAL_ID, &_format);
androiddisplay_cat.debug()
<< "Window format: " << _format << "\n";
_fbprops = best_props;
return;
}
androiddisplay_cat.error() <<
"Could not find a usable pixel format.\n";
delete[] configs;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::create_context
// Access: Private
// Description: Creates the context based on the config previously
// obtained in choose_pixel_format.
////////////////////////////////////////////////////////////////////
bool AndroidGraphicsStateGuardian::
create_context() {
if (_context != EGL_NO_CONTEXT) {
destroy_context();
}
#ifdef OPENGLES_2
EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
_context = eglCreateContext(_egl_display, _fbconfig, _share_context, context_attribs);
#else
_context = eglCreateContext(_egl_display, _fbconfig, _share_context, NULL);
#endif
int err = eglGetError();
if (_context != EGL_NO_CONTEXT && err == EGL_SUCCESS) {
_needs_reset = true;
return true;
}
androiddisplay_cat.error()
<< "Could not create EGL context!\n"
<< get_egl_error_string(err) << "\n";
return false;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::destroy_context
// Access: Private
// Description: Destroys the context previously created by
// create_context.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsStateGuardian::
destroy_context() {
if (_context == EGL_NO_CONTEXT) {
return;
}
if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
androiddisplay_cat.error() << "Failed to call eglMakeCurrent: "
<< get_egl_error_string(eglGetError()) << "\n";
}
release_all();
eglDestroyContext(_egl_display, _context);
_context = EGL_NO_CONTEXT;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::reset
// Access: Public, Virtual
// Description: Resets all internal state as if the gsg were newly
// created.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsStateGuardian::
reset() {
#ifdef OPENGLES_2
GLES2GraphicsStateGuardian::reset();
#else
GLESGraphicsStateGuardian::reset();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::egl_is_at_least_version
// Access: Public
// Description: Returns true if the runtime GLX version number is at
// least the indicated value, false otherwise.
////////////////////////////////////////////////////////////////////
bool AndroidGraphicsStateGuardian::
egl_is_at_least_version(int major_version, int minor_version) const {
if (_egl_version_major < major_version) {
return false;
}
if (_egl_version_minor < minor_version) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::gl_flush
// Access: Protected, Virtual
// Description: Calls glFlush().
////////////////////////////////////////////////////////////////////
void AndroidGraphicsStateGuardian::
gl_flush() const {
#ifdef OPENGLES_2
GLES2GraphicsStateGuardian::gl_flush();
#else
GLESGraphicsStateGuardian::gl_flush();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::gl_get_error
// Access: Protected, Virtual
// Description: Returns the result of glGetError().
////////////////////////////////////////////////////////////////////
GLenum AndroidGraphicsStateGuardian::
gl_get_error() const {
#ifdef OPENGLES_2
return GLES2GraphicsStateGuardian::gl_get_error();
#else
return GLESGraphicsStateGuardian::gl_get_error();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::query_gl_version
// Access: Protected, Virtual
// Description: Queries the runtime version of OpenGL in use.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsStateGuardian::
query_gl_version() {
#ifdef OPENGLES_2
GLES2GraphicsStateGuardian::query_gl_version();
#else
GLESGraphicsStateGuardian::query_gl_version();
#endif
// Calling eglInitialize on an already-initialized display will
// just provide us the version numbers.
if (!eglInitialize(_egl_display, &_egl_version_major, &_egl_version_minor)) {
androiddisplay_cat.error() << "Failed to get EGL version number: "
<< get_egl_error_string(eglGetError()) << "\n";
}
// We output to glesgsg_cat instead of androiddisplay_cat, since this is
// where the GL version has been output, and it's nice to see the
// two of these together.
#ifdef OPENGLES_2
if (gles2gsg_cat.is_debug()) {
gles2gsg_cat.debug()
#else
if (glesgsg_cat.is_debug()) {
glesgsg_cat.debug()
#endif
<< "EGL_VERSION = " << _egl_version_major << "." << _egl_version_minor
<< "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::get_extra_extensions
// Access: Protected, Virtual
// Description: This may be redefined by a derived class (e.g. glx or
// wgl) to get whatever further extensions strings may
// be appropriate to that interface, in addition to the
// GL extension strings return by glGetString().
////////////////////////////////////////////////////////////////////
void AndroidGraphicsStateGuardian::
get_extra_extensions() {
save_extensions(eglQueryString(_egl_display, EGL_EXTENSIONS));
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsStateGuardian::do_get_extension_func
// Access: Public, Virtual
// Description: Returns the pointer to the GL extension function with
// the indicated name. It is the responsibility of the
// caller to ensure that the required extension is
// defined in the OpenGL runtime prior to calling this;
// it is an error to call this for a function that is
// not defined.
////////////////////////////////////////////////////////////////////
void *AndroidGraphicsStateGuardian::
do_get_extension_func(const char *prefix, const char *name) {
string fullname = string(prefix) + string(name);
return (void *)eglGetProcAddress(fullname.c_str());
}

View File

@ -0,0 +1,97 @@
// Filename: androidGraphicsStateGuardian.h
// Created by: pro-rsoft (21May09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef ANDROIDGRAPHICSSTATEGUARDIAN_H
#define ANDROIDGRAPHICSSTATEGUARDIAN_H
#include "pandabase.h"
#include "androidGraphicsPipe.h"
////////////////////////////////////////////////////////////////////
// Class : AndroidGraphicsStateGuardian
// Description : A tiny specialization on GLESGraphicsStateGuardian
// to add some egl-specific information.
////////////////////////////////////////////////////////////////////
#ifdef OPENGLES_2
class AndroidGraphicsStateGuardian : public GLES2GraphicsStateGuardian {
#else
class AndroidGraphicsStateGuardian : public GLESGraphicsStateGuardian {
#endif
public:
INLINE const FrameBufferProperties &get_fb_properties() const;
void get_properties(FrameBufferProperties &properties,
bool &pbuffer_supported, bool &pixmap_supported,
bool &slow, EGLConfig config);
void choose_pixel_format(const FrameBufferProperties &properties,
bool need_pbuffer, bool need_pixmap);
bool create_context();
void destroy_context();
AndroidGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
AndroidGraphicsStateGuardian *share_with);
virtual ~AndroidGraphicsStateGuardian();
virtual void reset();
bool egl_is_at_least_version(int major_version, int minor_version) const;
protected:
EGLContext _share_context;
EGLContext _context;
EGLDisplay _egl_display;
EGLConfig _fbconfig;
EGLint _format;
FrameBufferProperties _fbprops;
protected:
virtual void gl_flush() const;
virtual GLenum gl_get_error() const;
virtual void query_gl_version();
virtual void get_extra_extensions();
virtual void *do_get_extension_func(const char *prefix, const char *name);
private:
int _egl_version_major, _egl_version_minor;
friend class AndroidGraphicsWindow;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
#ifdef OPENGLES_2
GLES2GraphicsStateGuardian::init_type();
register_type(_type_handle, "AndroidGraphicsStateGuardian",
GLES2GraphicsStateGuardian::get_class_type());
#else
GLESGraphicsStateGuardian::init_type();
register_type(_type_handle, "AndroidGraphicsStateGuardian",
GLESGraphicsStateGuardian::get_class_type());
#endif
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "androidGraphicsStateGuardian.I"
#endif

View File

@ -0,0 +1,14 @@
// Filename: androidGraphicsWindow.I
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,771 @@
// Filename: androidGraphicsWindow.cxx
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "androidGraphicsWindow.h"
#include "androidGraphicsStateGuardian.h"
#include "config_androiddisplay.h"
#include "androidGraphicsPipe.h"
#include "graphicsPipe.h"
#include "keyboardButton.h"
#include "mouseButton.h"
#include "clockObject.h"
#include "pStatTimer.h"
#include "textEncoder.h"
#include "throw_event.h"
#include "nativeWindowHandle.h"
#include "android_native_app_glue.h"
#include <android/window.h>
#include <android/log.h>
extern struct android_app* panda_android_app;
TypeHandle AndroidGraphicsWindow::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
AndroidGraphicsWindow::
AndroidGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
const string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg,
GraphicsOutput *host) :
GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
{
AndroidGraphicsPipe *android_pipe;
DCAST_INTO_V(android_pipe, _pipe);
_egl_display = android_pipe->_egl_display;
_egl_surface = 0;
_app = panda_android_app;
GraphicsWindowInputDevice device =
GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse");
add_input_device(device);
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
AndroidGraphicsWindow::
~AndroidGraphicsWindow() {
destroy_surface();
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::begin_frame
// Access: Public, Virtual
// Description: This function will be called within the draw thread
// before beginning rendering for a given frame. It
// should do whatever setup is required, and return true
// if the frame should be rendered, or false if it
// should be skipped.
////////////////////////////////////////////////////////////////////
bool AndroidGraphicsWindow::
begin_frame(FrameMode mode, Thread *current_thread) {
PStatTimer timer(_make_current_pcollector, current_thread);
begin_frame_spam(mode);
if (_gsg == (GraphicsStateGuardian *)NULL) {
return false;
}
//XXX not open yet.
if (_egl_surface == EGL_NO_SURFACE) {
return false;
}
AndroidGraphicsStateGuardian *androidgsg;
DCAST_INTO_R(androidgsg, _gsg, false);
{
if (eglGetCurrentDisplay() == _egl_display &&
eglGetCurrentSurface(EGL_READ) == _egl_surface &&
eglGetCurrentSurface(EGL_DRAW) == _egl_surface &&
eglGetCurrentContext() == androidgsg->_context) {
// No need to make the context current again. Short-circuit
// this possibly-expensive call.
} else {
// Need to set the context.
if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
androiddisplay_cat.error() << "Failed to call eglMakeCurrent: "
<< get_egl_error_string(eglGetError()) << "\n";
}
}
}
// Now that we have made the context current to a window, we can
// reset the GSG state if this is the first time it has been used.
// (We can't just call reset() when we construct the GSG, because
// reset() requires having a current context.)
androidgsg->reset_if_new();
if (mode == FM_render) {
// begin_render_texture();
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame(current_thread);
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::end_frame
// Access: Public, Virtual
// Description: This function will be called within the draw thread
// after rendering is completed for a given frame. It
// should do whatever finalization is required.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsWindow::
end_frame(FrameMode mode, Thread *current_thread) {
end_frame_spam(mode);
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
if (mode == FM_render) {
// end_render_texture();
copy_to_textures();
}
_gsg->end_frame(current_thread);
if (mode == FM_render) {
trigger_flip();
clear_cube_map_selection();
}
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::end_flip
// Access: Public, Virtual
// Description: This function will be called within the draw thread
// after begin_flip() has been called on all windows, to
// finish the exchange of the front and back buffers.
//
// This should cause the window to wait for the flip, if
// necessary.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsWindow::
end_flip() {
if (_gsg != (GraphicsStateGuardian *)NULL && _flip_ready) {
// It doesn't appear to be necessary to ensure the graphics
// context is current before flipping the windows, and insisting
// on doing so can be a significant performance hit.
//make_current();
if (_egl_surface != EGL_NO_SURFACE) {
eglSwapBuffers(_egl_display, _egl_surface);
}
}
GraphicsWindow::end_flip();
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::process_events
// Access: Public, Virtual
// Description: Do whatever processing is necessary to ensure that
// the window responds to user events. Also, honor any
// requests recently made via request_properties()
//
// This function is called only within the window
// thread.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsWindow::
process_events() {
GraphicsWindow::process_events();
// Read all pending events.
int looper_id;
int events;
struct android_poll_source* source;
// Loop until all events are read.
while ((looper_id = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0) {
// Process this event.
if (source != NULL) {
source->process(_app, source);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::set_properties_now
// Access: Public, Virtual
// Description: Applies the requested set of properties to the
// window, if possible, for instance to request a change
// in size or minimization status.
//
// The window properties are applied immediately, rather
// than waiting until the next frame. This implies that
// this method may *only* be called from within the
// window thread.
//
// The return value is true if the properties are set,
// false if they are ignored. This is mainly useful for
// derived classes to implement extensions to this
// function.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsWindow::
set_properties_now(WindowProperties &properties) {
if (_pipe == (GraphicsPipe *)NULL) {
// If the pipe is null, we're probably closing down.
GraphicsWindow::set_properties_now(properties);
return;
}
GraphicsWindow::set_properties_now(properties);
if (!properties.is_any_specified()) {
// The base class has already handled this case.
return;
}
// There's not really much we can change on Android.
if (properties.has_fullscreen()) {
uint32_t add_flags = 0;
uint32_t del_flags = 0;
if (_properties.get_fullscreen()) {
add_flags |= AWINDOW_FLAG_FULLSCREEN;
} else {
del_flags |= AWINDOW_FLAG_FULLSCREEN;
}
ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
_properties.set_fullscreen(properties.get_fullscreen());
properties.clear_fullscreen();
}
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::close_window
// Access: Protected, Virtual
// Description: Closes the window right now. Called from the window
// thread.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsWindow::
close_window() {
destroy_surface();
if (_gsg != (GraphicsStateGuardian *)NULL) {
_gsg.clear();
}
GraphicsWindow::close_window();
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::open_window
// Access: Protected, Virtual
// Description: Opens the window right now. Called from the window
// thread. Returns true if the window is successfully
// opened, or false if there was a problem.
////////////////////////////////////////////////////////////////////
bool AndroidGraphicsWindow::
open_window() {
// GSG Creation/Initialization
AndroidGraphicsStateGuardian *androidgsg;
if (_gsg == 0) {
// There is no old gsg. Create a new one.
androidgsg = new AndroidGraphicsStateGuardian(_engine, _pipe, NULL);
androidgsg->choose_pixel_format(_fb_properties, false, false);
_gsg = androidgsg;
} else {
// If the old gsg has the wrong pixel format, create a
// new one that shares with the old gsg.
DCAST_INTO_R(androidgsg, _gsg, false);
if (!androidgsg->get_fb_properties().subsumes(_fb_properties)) {
androidgsg = new AndroidGraphicsStateGuardian(_engine, _pipe, androidgsg);
androidgsg->choose_pixel_format(_fb_properties, false, false);
_gsg = androidgsg;
}
}
// Register the callbacks
assert(_app != NULL);
_app->userData = this;
_app->onAppCmd = handle_command;
_app->onInputEvent = handle_input_event;
// Wait until Android has opened the window.
while (_app->window == NULL) {
process_events();
}
// create_surface should have been called by now.
if (_egl_surface == EGL_NO_SURFACE) {
return false;
}
// Set some other properties.
_properties.set_origin(0, 0);
_properties.set_cursor_hidden(true);
_properties.set_undecorated(true);
if (!androidgsg->get_fb_properties().verify_hardware_software
(_fb_properties, androidgsg->get_gl_renderer())) {
close_window();
return false;
}
//_fb_properties = androidgsg->get_fb_properties();
androiddisplay_cat.error() << "open_window done\n";
return true;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::destroy_surface
// Access: Protected, Virtual
// Description: Terminates the EGL surface.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsWindow::
destroy_surface() {
if (_egl_surface != EGL_NO_SURFACE) {
if (!eglDestroySurface(_egl_display, _egl_surface)) {
androiddisplay_cat.error() << "Failed to destroy surface: "
<< get_egl_error_string(eglGetError()) << "\n";
}
_egl_surface = EGL_NO_SURFACE;
}
// Destroy the current context.
if (_gsg != (GraphicsStateGuardian *)NULL) {
AndroidGraphicsStateGuardian *androidgsg;
DCAST_INTO_V(androidgsg, _gsg);
androidgsg->destroy_context();
}
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::create_surface
// Access: Protected, Virtual
// Description: Creates the EGL surface.
////////////////////////////////////////////////////////////////////
bool AndroidGraphicsWindow::
create_surface() {
AndroidGraphicsStateGuardian *androidgsg;
DCAST_INTO_R(androidgsg, _gsg, false);
// Reconfigure the window buffers to match that of our framebuffer config.
ANativeWindow_setBuffersGeometry(_app->window, 0, 0, androidgsg->_format);
// Set any window flags
uint32_t add_flags = 0;
uint32_t del_flags = 0;
if (_properties.get_fullscreen()) {
add_flags |= AWINDOW_FLAG_FULLSCREEN;
} else {
del_flags |= AWINDOW_FLAG_FULLSCREEN;
}
ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
// Create the EGL surface.
_egl_surface = eglCreateWindowSurface(_egl_display, androidgsg->_fbconfig, _app->window, NULL);
if (eglGetError() != EGL_SUCCESS) {
androiddisplay_cat.error()
<< "Failed to create window surface.\n";
return false;
}
// Create a context.
if (androidgsg->_context == EGL_NO_CONTEXT) {
androiddisplay_cat.error() << "creating context\n";
if (!androidgsg->create_context()) {
return false;
}
}
// Switch to our newly created context.
if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
androiddisplay_cat.error() << "Failed to call eglMakeCurrent: "
<< get_egl_error_string(eglGetError()) << "\n";
}
// Query the size of the surface.
//EGLint width, height;
//eglQuerySurface(_egl_display, _egl_surface, EGL_WIDTH, &width);
//eglQuerySurface(_egl_display, _egl_surface, EGL_HEIGHT, &height);
androidgsg->reset_if_new();
if (!androidgsg->is_valid()) {
close_window();
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::handle_command
// Access: Private, Static
// Description: Android app sends a command from the main thread.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsWindow::
handle_command(struct android_app *app, int32_t command) {
AndroidGraphicsWindow* window = (AndroidGraphicsWindow*) app->userData;
window->ns_handle_command(command);
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::ns_handle_command
// Access: Private
// Description: Android app sends a command from the main thread.
////////////////////////////////////////////////////////////////////
void AndroidGraphicsWindow::
ns_handle_command(int32_t command) {
WindowProperties properties;
switch (command) {
case APP_CMD_SAVE_STATE:
// The system has asked us to save our current state. Do so.
//engine->app->savedState = malloc(sizeof(struct saved_state));
//*((struct saved_state*)engine->app->savedState) = engine->state;
//engine->app->savedStateSize = sizeof(struct saved_state);
break;
case APP_CMD_INIT_WINDOW:
// The window is being shown, get it ready.
if (_app->window != NULL) {
create_surface();
properties.set_minimized(false);
system_changed_properties(properties);
}
break;
case APP_CMD_TERM_WINDOW:
destroy_surface();
properties.set_minimized(true);
system_changed_properties(properties);
break;
case APP_CMD_WINDOW_RESIZED:
break;
case APP_CMD_WINDOW_REDRAW_NEEDED:
break;
case APP_CMD_CONTENT_RECT_CHANGED:
properties.set_origin(_app->contentRect.left, _app->contentRect.top);
properties.set_size(_app->contentRect.right - _app->contentRect.left,
_app->contentRect.bottom - _app->contentRect.top);
system_changed_properties(properties);
break;
case APP_CMD_GAINED_FOCUS:
properties.set_foreground(true);
system_changed_properties(properties);
break;
case APP_CMD_LOST_FOCUS:
properties.set_foreground(false);
system_changed_properties(properties);
break;
case APP_CMD_DESTROY:
close_window();
properties.set_open(false);
system_changed_properties(properties);
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::handle_input_event
// Access: Private, Static
// Description: Processes an input event. Returns 1 if the event
// was handled, 0 otherwise.
////////////////////////////////////////////////////////////////////
int32_t AndroidGraphicsWindow::
handle_input_event(struct android_app* app, AInputEvent *event) {
AndroidGraphicsWindow* window = (AndroidGraphicsWindow*) app->userData;
int32_t event_type = AInputEvent_getType(event);
switch (event_type) {
case AINPUT_EVENT_TYPE_KEY:
return window->handle_key_event(event);
case AINPUT_EVENT_TYPE_MOTION:
return window->handle_motion_event(event);
}
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::handle_keystroke
// Access: Private
// Description: Processes a key event.
////////////////////////////////////////////////////////////////////
int32_t AndroidGraphicsWindow::
handle_key_event(const AInputEvent *event) {
/*
int32_t meta = AKeyEvent_getMetaState(event);
if (meta | AMETA_ALT_ON) {
_input_devices[0].button_down(KeyboardButton.alt());
}
if (meta | AMETA_ALT_LEFT_ON) {
_input_devices[0].button_down(KeyboardButton.lalt());
}
if (meta | AMETA_ALT_RIGHT_ON) {
_input_devices[0].button_down(KeyboardButton.ralt());
}
if (meta | AMETA_SHIFT_ON) {
_input_devices[0].button_down(KeyboardButton.shift());
}
if (meta | AMETA_SHIFT_LEFT_ON) {
_input_devices[0].button_down(KeyboardButton.lshift());
}
if (meta | AMETA_SHIFT_RIGHT_ON) {
_input_devices[0].button_down(KeyboardButton.rshift());
}*/
int32_t keycode = AKeyEvent_getKeyCode(event);
ButtonHandle button = map_button(keycode);
if (button == ButtonHandle::none()) {
androiddisplay_cat.warning()
<< "Unknown keycode: " << keycode << "\n";
return 0;
}
// Is it an up or down event?
int32_t action = AKeyEvent_getAction(event);
if (action == AKEY_EVENT_ACTION_DOWN) {
_input_devices[0].button_down(button);
} else if (action == AKEY_EVENT_ACTION_UP) {
_input_devices[0].button_up(button);
}
//TODO getRepeatCount, ACTION_MULTIPLE
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::handle_motion_event
// Access: Private
// Description: Processes a motion event.
////////////////////////////////////////////////////////////////////
int32_t AndroidGraphicsWindow::
handle_motion_event(const AInputEvent *event) {
int32_t action = AMotionEvent_getAction(event);
action &= AMOTION_EVENT_ACTION_MASK;
if (action == AMOTION_EVENT_ACTION_DOWN) {
_input_devices[0].button_down(MouseButton::one());
} else if (action == AMOTION_EVENT_ACTION_UP) {
_input_devices[0].button_up(MouseButton::one());
}
float x = AMotionEvent_getX(event, 0);
float y = AMotionEvent_getY(event, 0);
_input_devices[0].set_pointer_in_window(x, y);
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: AndroidGraphicsWindow::map_button
// Access: Private
// Description: Given an Android keycode, returns an appropriate
// ButtonHandle object, or ButtonHandle::none() if
// a matching ButtonHandle does not exist.
////////////////////////////////////////////////////////////////////
ButtonHandle AndroidGraphicsWindow::
map_button(int32_t keycode) {
switch (keycode) {
case AKEYCODE_SOFT_LEFT:
case AKEYCODE_SOFT_RIGHT:
case AKEYCODE_HOME:
case AKEYCODE_BACK:
case AKEYCODE_CALL:
case AKEYCODE_ENDCALL:
break;
case AKEYCODE_0:
return KeyboardButton::ascii_key('0');
case AKEYCODE_1:
return KeyboardButton::ascii_key('1');
case AKEYCODE_2:
return KeyboardButton::ascii_key('2');
case AKEYCODE_3:
return KeyboardButton::ascii_key('3');
case AKEYCODE_4:
return KeyboardButton::ascii_key('4');
case AKEYCODE_5:
return KeyboardButton::ascii_key('5');
case AKEYCODE_6:
return KeyboardButton::ascii_key('6');
case AKEYCODE_7:
return KeyboardButton::ascii_key('7');
case AKEYCODE_8:
return KeyboardButton::ascii_key('8');
case AKEYCODE_9:
return KeyboardButton::ascii_key('9');
case AKEYCODE_STAR:
return KeyboardButton::ascii_key('*');
case AKEYCODE_POUND:
return KeyboardButton::ascii_key('#');
case AKEYCODE_DPAD_UP:
return KeyboardButton::up();
case AKEYCODE_DPAD_DOWN:
return KeyboardButton::down();
case AKEYCODE_DPAD_LEFT:
return KeyboardButton::left();
case AKEYCODE_DPAD_RIGHT:
return KeyboardButton::right();
case AKEYCODE_DPAD_CENTER:
case AKEYCODE_VOLUME_UP:
case AKEYCODE_VOLUME_DOWN:
case AKEYCODE_POWER:
case AKEYCODE_CAMERA:
case AKEYCODE_CLEAR:
break;
case AKEYCODE_A:
return KeyboardButton::ascii_key('a');
case AKEYCODE_B:
return KeyboardButton::ascii_key('b');
case AKEYCODE_C:
return KeyboardButton::ascii_key('c');
case AKEYCODE_D:
return KeyboardButton::ascii_key('d');
case AKEYCODE_E:
return KeyboardButton::ascii_key('e');
case AKEYCODE_F:
return KeyboardButton::ascii_key('f');
case AKEYCODE_G:
return KeyboardButton::ascii_key('g');
case AKEYCODE_H:
return KeyboardButton::ascii_key('h');
case AKEYCODE_I:
return KeyboardButton::ascii_key('i');
case AKEYCODE_J:
return KeyboardButton::ascii_key('j');
case AKEYCODE_K:
return KeyboardButton::ascii_key('k');
case AKEYCODE_L:
return KeyboardButton::ascii_key('l');
case AKEYCODE_M:
return KeyboardButton::ascii_key('m');
case AKEYCODE_N:
return KeyboardButton::ascii_key('n');
case AKEYCODE_O:
return KeyboardButton::ascii_key('o');
case AKEYCODE_P:
return KeyboardButton::ascii_key('p');
case AKEYCODE_Q:
return KeyboardButton::ascii_key('q');
case AKEYCODE_R:
return KeyboardButton::ascii_key('r');
case AKEYCODE_S:
return KeyboardButton::ascii_key('s');
case AKEYCODE_T:
return KeyboardButton::ascii_key('t');
case AKEYCODE_U:
return KeyboardButton::ascii_key('u');
case AKEYCODE_V:
return KeyboardButton::ascii_key('v');
case AKEYCODE_W:
return KeyboardButton::ascii_key('w');
case AKEYCODE_X:
return KeyboardButton::ascii_key('x');
case AKEYCODE_Y:
return KeyboardButton::ascii_key('y');
case AKEYCODE_Z:
return KeyboardButton::ascii_key('z');
case AKEYCODE_COMMA:
return KeyboardButton::ascii_key(',');
case AKEYCODE_PERIOD:
return KeyboardButton::ascii_key('.');
case AKEYCODE_ALT_LEFT:
return KeyboardButton::lalt();
case AKEYCODE_ALT_RIGHT:
return KeyboardButton::ralt();
case AKEYCODE_SHIFT_LEFT:
return KeyboardButton::lshift();
case AKEYCODE_SHIFT_RIGHT:
return KeyboardButton::rshift();
case AKEYCODE_TAB:
return KeyboardButton::tab();
case AKEYCODE_SPACE:
return KeyboardButton::space();
case AKEYCODE_SYM:
case AKEYCODE_EXPLORER:
case AKEYCODE_ENVELOPE:
break;
case AKEYCODE_ENTER:
return KeyboardButton::enter();
case AKEYCODE_DEL:
return KeyboardButton::del();
case AKEYCODE_GRAVE:
return KeyboardButton::ascii_key('`');
case AKEYCODE_MINUS:
return KeyboardButton::ascii_key('-');
case AKEYCODE_EQUALS:
return KeyboardButton::ascii_key('=');
case AKEYCODE_LEFT_BRACKET:
return KeyboardButton::ascii_key('[');
case AKEYCODE_RIGHT_BRACKET:
return KeyboardButton::ascii_key(']');
case AKEYCODE_BACKSLASH:
return KeyboardButton::ascii_key('\\');
case AKEYCODE_SEMICOLON:
return KeyboardButton::ascii_key(';');
case AKEYCODE_APOSTROPHE:
return KeyboardButton::ascii_key('\'');
case AKEYCODE_SLASH:
return KeyboardButton::ascii_key('/');
case AKEYCODE_AT:
return KeyboardButton::ascii_key('@');
case AKEYCODE_NUM:
case AKEYCODE_HEADSETHOOK:
case AKEYCODE_FOCUS:
break;
case AKEYCODE_PLUS:
return KeyboardButton::ascii_key('+');
case AKEYCODE_MENU:
case AKEYCODE_NOTIFICATION:
case AKEYCODE_SEARCH:
case AKEYCODE_MEDIA_PLAY_PAUSE:
case AKEYCODE_MEDIA_STOP:
case AKEYCODE_MEDIA_NEXT:
case AKEYCODE_MEDIA_PREVIOUS:
case AKEYCODE_MEDIA_REWIND:
case AKEYCODE_MEDIA_FAST_FORWARD:
case AKEYCODE_MUTE:
break;
case AKEYCODE_PAGE_UP:
return KeyboardButton::page_up();
case AKEYCODE_PAGE_DOWN:
return KeyboardButton::page_down();
case AKEYCODE_PICTSYMBOLS:
case AKEYCODE_SWITCH_CHARSET:
case AKEYCODE_BUTTON_A:
case AKEYCODE_BUTTON_B:
case AKEYCODE_BUTTON_C:
case AKEYCODE_BUTTON_X:
case AKEYCODE_BUTTON_Y:
case AKEYCODE_BUTTON_Z:
case AKEYCODE_BUTTON_L1:
case AKEYCODE_BUTTON_R1:
case AKEYCODE_BUTTON_L2:
case AKEYCODE_BUTTON_R2:
case AKEYCODE_BUTTON_THUMBL:
case AKEYCODE_BUTTON_THUMBR:
case AKEYCODE_BUTTON_START:
case AKEYCODE_BUTTON_SELECT:
case AKEYCODE_BUTTON_MODE:
default:
break;
}
return ButtonHandle::none();
}

View File

@ -0,0 +1,99 @@
// Filename: androidGraphicsWindow.h
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef ANDROIDGRAPHICSWINDOW_H
#define ANDROIDGRAPHICSWINDOW_H
#include "pandabase.h"
#include "androidGraphicsPipe.h"
#include "graphicsWindow.h"
#include "buttonHandle.h"
#include <android/native_window.h>
#include <android/input.h>
#include <android/native_activity.h>
#include <android/rect.h>
struct android_app;
////////////////////////////////////////////////////////////////////
// Class : AndroidGraphicsWindow
// Description : An interface to manage Android windows and their
// appropriate EGL surfaces.
////////////////////////////////////////////////////////////////////
class AndroidGraphicsWindow : public GraphicsWindow {
public:
AndroidGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
const string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg,
GraphicsOutput *host);
virtual ~AndroidGraphicsWindow();
virtual bool begin_frame(FrameMode mode, Thread *current_thread);
virtual void end_frame(FrameMode mode, Thread *current_thread);
virtual void end_flip();
virtual void process_events();
virtual void set_properties_now(WindowProperties &properties);
protected:
virtual void close_window();
virtual bool open_window();
virtual void destroy_surface();
virtual bool create_surface();
private:
static void handle_command(struct android_app *app, int32_t command);
static int32_t handle_input_event(struct android_app *app, AInputEvent *event);
void ns_handle_command(int32_t command);
int32_t handle_key_event(const AInputEvent *event);
int32_t handle_motion_event(const AInputEvent *event);
ButtonHandle map_button(int32_t keycode);
private:
struct android_app* _app;
EGLDisplay _egl_display;
EGLSurface _egl_surface;
const ARect *rect;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
GraphicsWindow::init_type();
register_type(_type_handle, "AndroidGraphicsWindow",
GraphicsWindow::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "androidGraphicsWindow.I"
#endif

View File

@ -0,0 +1,90 @@
// Filename: config_androiddisplay.cxx
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "config_androiddisplay.h"
#include "androidGraphicsPipe.h"
#include "androidGraphicsWindow.h"
#include "androidGraphicsStateGuardian.h"
#include "graphicsPipeSelection.h"
#include "dconfig.h"
#include "pandaSystem.h"
#include "config_display.h"
Configure(config_androiddisplay);
NotifyCategoryDef(androiddisplay, "display");
ConfigureFn(config_androiddisplay) {
init_libandroiddisplay();
}
////////////////////////////////////////////////////////////////////
// Function: init_libandroiddisplay
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libandroiddisplay() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
init_libdisplay();
display_cat.get_safe_ptr();
AndroidGraphicsPipe::init_type();
AndroidGraphicsWindow::init_type();
AndroidGraphicsStateGuardian::init_type();
GraphicsPipeSelection *selection = GraphicsPipeSelection::get_global_ptr();
selection->add_pipe_type(AndroidGraphicsPipe::get_class_type(),
AndroidGraphicsPipe::pipe_constructor);
PandaSystem *ps = PandaSystem::get_global_ptr();
#ifdef OPENGLES_2
ps->set_system_tag("OpenGL ES 2", "window_system", "Android");
#else
ps->set_system_tag("OpenGL ES", "window_system", "Android");
#endif
}
////////////////////////////////////////////////////////////////////
// Function: get_egl_error_string
// Description: Returns the given EGL error as string.
////////////////////////////////////////////////////////////////////
const string get_egl_error_string(int error) {
switch (error) {
case 0x3000: return "EGL_SUCCESS"; break;
case 0x3001: return "EGL_NOT_INITIALIZED"; break;
case 0x3002: return "EGL_BAD_ACCESS"; break;
case 0x3003: return "EGL_BAD_ALLOC"; break;
case 0x3004: return "EGL_BAD_ATTRIBUTE"; break;
case 0x3005: return "EGL_BAD_CONFIG"; break;
case 0x3006: return "EGL_BAD_CONTEXT"; break;
case 0x3007: return "EGL_BAD_CURRENT_SURFACE"; break;
case 0x3008: return "EGL_BAD_DISPLAY"; break;
case 0x3009: return "EGL_BAD_MATCH"; break;
case 0x300A: return "EGL_BAD_NATIVE_PIXMAP"; break;
case 0x300B: return "EGL_BAD_NATIVE_WINDOW"; break;
case 0x300C: return "EGL_BAD_PARAMETER"; break;
case 0x300D: return "EGL_BAD_SURFACE"; break;
case 0x300E: return "EGL_CONTEXT_LOST"; break;
default: return "Unknown error";
}
}

View File

@ -0,0 +1,43 @@
// Filename: config_androiddisplay.h
// Created by: rdb (11Jan13)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_ANDROIDDISPLAY_H
#define CONFIG_ANDROIDDISPLAY_H
#include "pandabase.h"
#include "notifyCategoryProxy.h"
#include "configVariableString.h"
#include "configVariableBool.h"
#include "configVariableInt.h"
#if defined(OPENGLES_1) && defined(OPENGLES_2)
#error OPENGLES_1 and OPENGLES_2 cannot be defined at the same time!
#endif
#if !defined(OPENGLES_1) && !defined(OPENGLES_2)
#error Either OPENGLES_1 or OPENGLES_2 must be defined when compiling androiddisplay!
#endif
#ifdef OPENGLES_2
NotifyCategoryDecl(androiddisplay, EXPCL_PANDAGLES2, EXPTP_PANDAGLES2);
extern EXPCL_PANDAGLES2 void init_libandroiddisplay();
extern EXPCL_PANDAGLES2 const string get_egl_error_string(int error);
#else
NotifyCategoryDecl(androiddisplay, EXPCL_PANDAGLES, EXPTP_PANDAGLES);
extern EXPCL_PANDAGLES void init_libandroiddisplay();
extern EXPCL_PANDAGLES const string get_egl_error_string(int error);
#endif
#endif

View File

@ -0,0 +1,6 @@
#include "config_androiddisplay.cxx"
//#include "androidGraphicsBuffer.cxx"
#include "androidGraphicsPipe.cxx"
//#include "androidGraphicsPixmap.cxx"
#include "androidGraphicsStateGuardian.cxx"
#include "androidGraphicsWindow.cxx"