--- /dev/null
+#include <vector>
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <android/native_window.h>
+#include "display.h"
+#include "glcontext.h"
+#include "window_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Graphics {
+
+struct GLContext::Private
+{
+ EGLDisplay display;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLContext context;
+
+ void attach(WindowHandle);
+ void detach();
+};
+
+
+void GLContext::platform_init(const GLOptions &opts)
+{
+ EGLDisplay egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if(egl_display==EGL_NO_DISPLAY)
+ throw runtime_error("no egl display");
+
+ if(!eglInitialize(egl_display, 0, 0))
+ throw runtime_error("could not initialize egl");
+
+ vector<int> attribs;
+
+ attribs.push_back(EGL_COLOR_BUFFER_TYPE);
+ attribs.push_back(EGL_RGB_BUFFER);
+ attribs.push_back(EGL_RENDERABLE_TYPE);
+ attribs.push_back(EGL_OPENGL_ES2_BIT);
+ attribs.push_back(EGL_SURFACE_TYPE);
+ attribs.push_back(EGL_WINDOW_BIT);
+ attribs.push_back(EGL_DEPTH_SIZE);
+ attribs.push_back(1);
+
+ if(opts.alpha)
+ {
+ attribs.push_back(EGL_ALPHA_SIZE);
+ attribs.push_back(1);
+ }
+
+ if(opts.stencil)
+ {
+ attribs.push_back(EGL_STENCIL_SIZE);
+ attribs.push_back(1);
+ }
+
+ if(opts.multisample>0)
+ {
+ attribs.push_back(EGL_SAMPLE_BUFFERS);
+ attribs.push_back(1);
+ attribs.push_back(EGL_SAMPLES);
+ attribs.push_back(opts.multisample);
+ }
+
+ attribs.push_back(EGL_NONE);
+
+ EGLConfig config;
+ int num_configs;
+ if(!eglChooseConfig(egl_display, &attribs.front(), &config, 1, &num_configs))
+ {
+ eglTerminate(egl_display);
+ throw unsupported_gl_mode(opts);
+ }
+
+ priv = new Private;
+ priv->display = egl_display;
+ priv->config = config;
+
+ /* Must wait for the window to be available, because the calling code
+ expects GL to be usable after creation of the context. */
+ WindowHandle native_window;
+ const Window::Private &window_priv = window.get_private();
+ while(!(native_window = window_priv.window))
+ display.tick();
+
+ int format;
+ eglGetConfigAttrib(priv->display, config, EGL_NATIVE_VISUAL_ID, &format);
+ ANativeWindow_setBuffersGeometry(native_window, 0, 0, format);
+
+ priv->surface = eglCreateWindowSurface(priv->display, config, native_window, 0);
+
+ eglBindAPI(EGL_OPENGL_ES_API);
+ int context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ priv->context = eglCreateContext(priv->display, config, 0, context_attribs);
+
+ eglMakeCurrent(priv->display, priv->surface, priv->surface, priv->context);
+
+ window_priv.signal_window_acquired.connect(sigc::mem_fun(priv, &Private::attach));
+ window_priv.signal_window_lost.connect(sigc::mem_fun(priv, &Private::detach));
+}
+
+GLContext::~GLContext()
+{
+ eglDestroyContext(priv->display, priv->context);
+ if(priv->surface!=EGL_NO_SURFACE)
+ eglDestroySurface(priv->display, priv->surface);
+ eglTerminate(priv->display);
+ delete priv;
+}
+
+void GLContext::swap_buffers()
+{
+ eglSwapBuffers(priv->display, priv->surface);
+}
+
+void GLContext::window_resized(unsigned w, unsigned h)
+{
+ glViewport(0, 0, w, h);
+}
+
+
+void GLContext::Private::attach(WindowHandle native_window)
+{
+ surface = eglCreateWindowSurface(display, config, native_window, 0);
+ eglMakeCurrent(display, surface, surface, context);
+}
+
+void GLContext::Private::detach()
+{
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(display, surface);
+}
+
+} // namespace Graphics
+} // namespace Msp