Browse Source

This is a big commit for OpenGL ES stuff:
* Added GLES, GLES2 and EGL packages to the ppremake files.
* New glesgsg and gles2gsg modules.
* Added egldisplay module that is like glxdisplay, but through the EGL library.
* Added pandagles and pandagles2 metalibs (only supporting egldisplay yet)
* The iphonedisplay module depends on glesgsg instead of embedding it.
* The glesext_shadow.h file is removed, we don't need it anymore.

rdb 16 years ago
parent
commit
b0c4875ad9
43 changed files with 4475 additions and 228 deletions
  1. 14 1
      dtool/LocalSetup.pp
  2. 14 0
      dtool/Package.pp
  3. 21 0
      dtool/pptempl/Global.pp
  4. 22 0
      panda/metalibs/pandagles/Sources.pp
  5. 51 0
      panda/metalibs/pandagles/pandagles.cxx
  6. 15 0
      panda/metalibs/pandagles/pandagles.h
  7. 22 0
      panda/metalibs/pandagles2/Sources.pp
  8. 51 0
      panda/metalibs/pandagles2/pandagles2.cxx
  9. 15 0
      panda/metalibs/pandagles2/pandagles2.h
  10. 50 0
      panda/src/egldisplay/Sources.pp
  11. 120 0
      panda/src/egldisplay/config_egldisplay.cxx
  12. 51 0
      panda/src/egldisplay/config_egldisplay.h
  13. 229 0
      panda/src/egldisplay/eglGraphicsBuffer.cxx
  14. 69 0
      panda/src/egldisplay/eglGraphicsBuffer.h
  15. 72 0
      panda/src/egldisplay/eglGraphicsPipe.I
  16. 429 0
      panda/src/egldisplay/eglGraphicsPipe.cxx
  17. 155 0
      panda/src/egldisplay/eglGraphicsPipe.h
  18. 258 0
      panda/src/egldisplay/eglGraphicsPixmap.cxx
  19. 73 0
      panda/src/egldisplay/eglGraphicsPixmap.h
  20. 26 0
      panda/src/egldisplay/eglGraphicsStateGuardian.I
  21. 376 0
      panda/src/egldisplay/eglGraphicsStateGuardian.cxx
  22. 99 0
      panda/src/egldisplay/eglGraphicsStateGuardian.h
  23. 24 0
      panda/src/egldisplay/eglGraphicsWindow.I
  24. 1684 0
      panda/src/egldisplay/eglGraphicsWindow.cxx
  25. 123 0
      panda/src/egldisplay/eglGraphicsWindow.h
  26. 20 0
      panda/src/gles2gsg/Sources.pp
  27. 44 0
      panda/src/gles2gsg/config_gles2gsg.cxx
  28. 27 0
      panda/src/gles2gsg/config_gles2gsg.h
  29. 20 0
      panda/src/gles2gsg/gles2gsg.cxx
  30. 74 0
      panda/src/gles2gsg/gles2gsg.h
  31. 1 0
      panda/src/gles2gsg/gles2gsg_composite.cxx
  32. 3 0
      panda/src/gles2gsg/gles2gsg_composite1.cxx
  33. 20 0
      panda/src/glesgsg/Sources.pp
  34. 44 0
      panda/src/glesgsg/config_glesgsg.cxx
  35. 27 0
      panda/src/glesgsg/config_glesgsg.h
  36. 5 1
      panda/src/glesgsg/glesgsg.cxx
  37. 100 0
      panda/src/glesgsg/glesgsg.h
  38. 1 0
      panda/src/glesgsg/glesgsg_composite.cxx
  39. 3 0
      panda/src/glesgsg/glesgsg_composite1.cxx
  40. 1 3
      panda/src/iphonedisplay/Sources.pp
  41. 0 174
      panda/src/iphonedisplay/glesext_shadow.h
  42. 0 49
      panda/src/iphonedisplay/glesgsg.h
  43. 22 0
      panda/src/pandabase/pandasymbols.h

+ 14 - 1
dtool/LocalSetup.pp

@@ -118,6 +118,10 @@
 #endif
 #if $[HAVE_GL]
 #print + OpenGL
+#elif $[HAVE_GLES2]
+#print + OpenGL ES 2
+#elif $[HAVE_GLES]
+#print + OpenGL ES
 #else
 #print - Did not find OpenGL
 #endif
@@ -326,6 +330,12 @@ $[cdefine HAVE_GLU]
 # define MIN_GL_VERSION_MINOR $[word 2,$[MIN_GL_VERSION]]
 #endif
 
+/* Define if we have OpenGL ES installed and want to build for GLES. */
+$[cdefine HAVE_GLES]
+
+/* Define if we have OpenGL ES installed and want to build for GLES2. */
+$[cdefine HAVE_GLES2]
+
 /* Define if we have OpenCV installed and want to build for OpenCV.  */
 $[cdefine HAVE_OPENCV]
 
@@ -346,6 +356,9 @@ $[cdefine MESA_MGL]
 /* Define if we have GLX installed and want to build for GLX.  */
 $[cdefine HAVE_GLX]
 
+/* Define if we have EGL installed and want to build for EGL.  */
+$[cdefine HAVE_EGL]
+
 /* Define if we have Windows-GL installed and want to build for Wgl.  */
 $[cdefine HAVE_WGL]
 
@@ -413,7 +426,7 @@ $[cdefine SUPPORT_IMMEDIATE_MODE]
 /* Define if we want to compile in support for pipelining.  */
 $[cdefine DO_PIPELINING]
 
-/* Define if we want to keep Notify debug messages around, or undefine 
+/* Define if we want to keep Notify debug messages around, or undefine
    to compile them out.  */
 $[cdefine NOTIFY_DEBUG]
 

+ 14 - 0
dtool/Package.pp

@@ -204,6 +204,16 @@
 #set HAVE_GL $[HAVE_GL]
 #set HAVE_GLU $[HAVE_GLU]
 
+#set GLES_IPATH $[unixfilename $[GLES_IPATH]]
+#set GLES_LPATH $[unixfilename $[GLES_LPATH]]
+#set GLES_LIBS $[GLES_LIBS]
+#set HAVE_GLES $[HAVE_GLES]
+
+#set GLES2_IPATH $[unixfilename $[GLES2_IPATH]]
+#set GLES2_LPATH $[unixfilename $[GLES2_LPATH]]
+#set GLES2_LIBS $[GLES2_LIBS]
+#set HAVE_GLES2 $[HAVE_GLES2]
+
 #set MESA_IPATH $[unixfilename $[MESA_IPATH]]
 #set MESA_LPATH $[unixfilename $[MESA_LPATH]]
 #set MESA_LIBS $[MESA_LIBS]
@@ -214,6 +224,10 @@
 #set GLX_LPATH $[unixfilename $[GLX_LPATH]]
 #set HAVE_GLX $[HAVE_GLX]
 
+#set EGL_IPATH $[unixfilename $[EGL_IPATH]]
+#set EGL_LPATH $[unixfilename $[EGL_LPATH]]
+#set HAVE_EGL $[HAVE_EGL]
+
 #set HAVE_WGL $[HAVE_WGL]
 
 #set DX8_IPATH $[unixfilename $[DX8_IPATH]]

+ 21 - 0
dtool/pptempl/Global.pp

@@ -113,6 +113,20 @@
   #define gl_framework $[GL_FRAMEWORK]
 #endif
 
+#if $[HAVE_GLES]
+  #define gles_ipath $[wildcard $[GLES_IPATH]]
+  #define gles_lpath $[wildcard $[GLES_LPATH]]
+  #define gles_cflags $[GLES_CFLAGS]
+  #define gles_libs $[GLES_LIBS]
+#endif
+
+#if $[HAVE_GLES2]
+  #define gles2_ipath $[wildcard $[GLES2_IPATH]]
+  #define gles2_lpath $[wildcard $[GLES2_LPATH]]
+  #define gles2_cflags $[GLES2_CFLAGS]
+  #define gles2_libs $[GLES2_LIBS]
+#endif
+
 #if $[HAVE_SDL]
   #define sdl_ipath $[wildcard $[SDL_IPATH]]
   #define sdl_lpath $[wildcard $[SDL_LPATH]]
@@ -150,6 +164,13 @@
   #define glx_libs $[GLX_LIBS]
 #endif
 
+#if $[HAVE_EGL]
+  #define egl_ipath $[wildcard $[EGL_IPATH]]
+  #define egl_lpath $[wildcard $[EGL_LPATH]]
+  #define egl_cflags $[EGL_CFLAGS]
+  #define egl_libs $[EGL_LIBS]
+#endif
+
 #if $[HAVE_GLUT]
   #define glut_ipath $[wildcard $[GLUT_IPATH]]
   #define glut_lpath $[wildcard $[GLUT_LPATH]]

+ 22 - 0
panda/metalibs/pandagles/Sources.pp

@@ -0,0 +1,22 @@
+// DIR_TYPE "metalib" indicates we are building a shared library that
+// consists mostly of references to other shared libraries.  Under
+// Windows, this directly produces a DLL (as opposed to the regular
+// src libraries, which don't produce anything but a pile of OBJ files
+// under Windows).
+
+#define DIR_TYPE metalib
+#define BUILDING_DLL BUILDING_PANDAGLES
+#define BUILD_DIRECTORY $[HAVE_GLES]
+
+#define COMPONENT_LIBS \
+    glesgsg egldisplay
+
+#define LOCAL_LIBS gsgbase display express
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+                   dtoolutil:c dtoolbase:c dtool:m prc:c
+
+#begin metalib_target
+  #define TARGET pandagles
+  #define SOURCES pandagles.cxx pandagles.h
+  #define INSTALL_HEADERS pandagles.h
+#end metalib_target

+ 51 - 0
panda/metalibs/pandagles/pandagles.cxx

@@ -0,0 +1,51 @@
+// Filename: pandagles.cxx
+// Created by:  pro-rsoft (8Jun09)
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandagles.h"
+
+#define OPENGLES_1
+#include "config_glesgsg.h"
+
+#ifdef HAVE_EGL
+#include "config_egldisplay.h"
+#include "eglGraphicsPipe.h"
+#endif
+
+// By including checkPandaVersion.h, we guarantee that runtime
+// attempts to load libpandagles.so/.dll will fail if they inadvertently
+// link with the wrong version of libdtool.so/.dll.
+
+#include "checkPandaVersion.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libpandagles
+//  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_libpandagles() {
+  init_libglesgsg();
+
+#ifdef HAVE_EGL
+  init_libegldisplay();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: get_pipe_type_pandagles
+//  Description: Returns the TypeHandle index of the recommended
+//               graphics pipe type defined by this module.
+////////////////////////////////////////////////////////////////////
+int
+get_pipe_type_pandagles() {
+#ifdef HAVE_EGL
+  return eglGraphicsPipe::get_class_type().get_index();
+#endif
+
+  return 0;
+}

+ 15 - 0
panda/metalibs/pandagles/pandagles.h

@@ -0,0 +1,15 @@
+// Filename: pandagles.h
+// Created by:  pro-rsoft (8Jun09)
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PANDAGLES_H
+#define PANDAGLES_H
+
+#include "pandabase.h"
+
+EXPCL_PANDAGLES void init_libpandagles();
+extern "C" EXPCL_PANDAGLES int get_pipe_type_pandagles();
+
+#endif
+

+ 22 - 0
panda/metalibs/pandagles2/Sources.pp

@@ -0,0 +1,22 @@
+// DIR_TYPE "metalib" indicates we are building a shared library that
+// consists mostly of references to other shared libraries.  Under
+// Windows, this directly produces a DLL (as opposed to the regular
+// src libraries, which don't produce anything but a pile of OBJ files
+// under Windows).
+
+#define DIR_TYPE metalib
+#define BUILDING_DLL BUILDING_PANDAGLES
+#define BUILD_DIRECTORY $[HAVE_GLES2]
+
+#define COMPONENT_LIBS \
+    gles2gsg egl2display
+
+#define LOCAL_LIBS gsgbase display express
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+                   dtoolutil:c dtoolbase:c dtool:m prc:c
+
+#begin metalib_target
+  #define TARGET pandagles2
+  #define SOURCES pandagles2.cxx pandagles2.h
+  #define INSTALL_HEADERS pandagles2.h
+#end metalib_target

+ 51 - 0
panda/metalibs/pandagles2/pandagles2.cxx

@@ -0,0 +1,51 @@
+// Filename: pandagles2.cxx
+// Created by:  pro-rsoft (8Jun09)
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandagles2.h"
+
+#define OPENGLES_2
+#include "config_gles2gsg.h"
+
+#ifdef HAVE_EGL
+#include "config_egldisplay.h"
+#include "eglGraphicsPipe.h"
+#endif
+
+// By including checkPandaVersion.h, we guarantee that runtime
+// attempts to load libpandagles2.so/.dll will fail if they inadvertently
+// link with the wrong version of libdtool.so/.dll.
+
+#include "checkPandaVersion.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libpandagles2
+//  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_libpandagles2() {
+  init_libgles2gsg();
+
+#ifdef HAVE_EGL
+  init_libegldisplay();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: get_pipe_type_pandagles2
+//  Description: Returns the TypeHandle index of the recommended
+//               graphics pipe type defined by this module.
+////////////////////////////////////////////////////////////////////
+int
+get_pipe_type_pandagles2() {
+#ifdef HAVE_EGL
+  return eglGraphicsPipe::get_class_type().get_index();
+#endif
+
+  return 0;
+}

+ 15 - 0
panda/metalibs/pandagles2/pandagles2.h

@@ -0,0 +1,15 @@
+// Filename: pandagles.h
+// Created by:  pro-rsoft (16Jun09)
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PANDAGLES2_H
+#define PANDAGLES2_H
+
+#include "pandabase.h"
+
+EXPCL_PANDAGLES2 void init_libpandagles2();
+extern "C" EXPCL_PANDAGLES2 int get_pipe_type_pandagles2();
+
+#endif
+

+ 50 - 0
panda/src/egldisplay/Sources.pp

@@ -0,0 +1,50 @@
+#define BUILD_DIRECTORY $[HAVE_EGL]
+
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+                   dtoolutil:c dtoolbase:c dtool:m
+
+#begin lib_target
+  #define TARGET egldisplay
+  #define BUILD_TARGET $[HAVE_GLES]
+  #define USE_PACKAGES gles egl x11
+  #define C++FLAGS -DOPENGLES_1
+  #define LOCAL_LIBS \
+    glesgsg
+
+  #define SOURCES \
+    config_egldisplay.cxx config_egldisplay.h \
+    eglGraphicsBuffer.h eglGraphicsBuffer.cxx \
+    eglGraphicsPipe.I eglGraphicsPipe.cxx eglGraphicsPipe.h \
+    eglGraphicsPixmap.h eglGraphicsPixmap.cxx \
+    eglGraphicsWindow.h eglGraphicsWindow.cxx \
+    eglGraphicsStateGuardian.h eglGraphicsStateGuardian.cxx
+
+  #define INSTALL_HEADERS \
+    eglGraphicsBuffer.h eglGraphicsPixmap.h \
+    eglGraphicsPipe.I eglGraphicsPipe.h \
+    eglGraphicsWindow.I eglGraphicsWindow.h
+
+#end lib_target
+
+#begin lib_target
+  #define TARGET egl2display
+  #define BUILD_TARGET $[HAVE_GLES2]
+  #define USE_PACKAGES gles2 egl x11
+  #define C++FLAGS -DOPENGLES_2
+  #define LOCAL_LIBS \
+    gles2gsg
+
+  #define SOURCES \
+    config_egldisplay.cxx config_egldisplay.h \
+    eglGraphicsBuffer.h eglGraphicsBuffer.cxx \
+    eglGraphicsPipe.I eglGraphicsPipe.cxx eglGraphicsPipe.h \
+    eglGraphicsPixmap.h eglGraphicsPixmap.cxx \
+    eglGraphicsWindow.h eglGraphicsWindow.cxx \
+    eglGraphicsStateGuardian.h eglGraphicsStateGuardian.cxx
+
+  #define INSTALL_HEADERS \
+    eglGraphicsBuffer.h eglGraphicsPixmap.h \
+    eglGraphicsPipe.I eglGraphicsPipe.h \
+    eglGraphicsWindow.I eglGraphicsWindow.h
+
+#end lib_target

+ 120 - 0
panda/src/egldisplay/config_egldisplay.cxx

@@ -0,0 +1,120 @@
+// Filename: config_egldisplay.cxx
+// Created by:  cary (07Oct99)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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_egldisplay.h"
+#include "eglGraphicsPipe.h"
+#include "eglGraphicsWindow.h"
+#include "eglGraphicsStateGuardian.h"
+#include "graphicsPipeSelection.h"
+#include "dconfig.h"
+#include "pandaSystem.h"
+
+Configure(config_egldisplay);
+NotifyCategoryDef(egldisplay, "display");
+
+ConfigureFn(config_egldisplay) {
+  init_libegldisplay();
+}
+
+ConfigVariableString display_cfg
+("display", "",
+ PRC_DESC("Specify the X display string for the default display.  If this "
+          "is not specified, $DISPLAY is used."));
+
+ConfigVariableBool x_error_abort
+("x-error-abort", false,
+ PRC_DESC("Set this true to trigger and abort (and a stack trace) on receipt "
+          "of an error from the X window system.  This can make it easier "
+          "to discover where these errors are generated."));
+
+ConfigVariableInt x_wheel_up_button
+("x-wheel-up-button", 4,
+ PRC_DESC("This is the mouse button index of the wheel_up event: which "
+          "mouse button number does the system report when the mouse wheel "
+          "is rolled one notch up?"));
+
+ConfigVariableInt x_wheel_down_button
+("x-wheel-down-button", 5,
+ PRC_DESC("This is the mouse button index of the wheel_down event: which "
+          "mouse button number does the system report when the mouse wheel "
+          "is rolled one notch down?"));
+
+ConfigVariableInt x_wheel_left_button
+("x-wheel-left-button", 6,
+ PRC_DESC("This is the mouse button index of the wheel_left event: which "
+          "mouse button number does the system report when one scrolls "
+          "to the left?"));
+
+ConfigVariableInt x_wheel_right_button
+("x-wheel-right-button", 7,
+ PRC_DESC("This is the mouse button index of the wheel_right event: which "
+          "mouse button number does the system report when one scrolls "
+          "to the right?"));
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libegldisplay
+//  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_libegldisplay() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+
+  eglGraphicsPipe::init_type();
+  eglGraphicsWindow::init_type();
+  eglGraphicsStateGuardian::init_type();
+
+  GraphicsPipeSelection *selection = GraphicsPipeSelection::get_global_ptr();
+  selection->add_pipe_type(eglGraphicsPipe::get_class_type(),
+                           eglGraphicsPipe::pipe_constructor);
+
+  PandaSystem *ps = PandaSystem::get_global_ptr();
+#ifdef OPENGLES_2
+  ps->set_system_tag("OpenGL ES 2", "window_system", "EGL");
+#else
+  ps->set_system_tag("OpenGL ES", "window_system", "EGL");
+#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";
+  }
+}

+ 51 - 0
panda/src/egldisplay/config_egldisplay.h

@@ -0,0 +1,51 @@
+// Filename: config_egldisplay.h
+// Created by:  cary (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 CONFIG_EGLDISPLAY_H
+#define CONFIG_EGLDISPLAY_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 egldisplay!
+#endif
+
+#ifdef OPENGLES_2
+  NotifyCategoryDecl(egldisplay, EXPCL_PANDAGLES2, EXPTP_PANDAGLES2);
+  
+  extern EXPCL_PANDAGLES2 void init_libegldisplay();
+  extern EXPCL_PANDAGLES2 const string get_egl_error_string(int error);
+#else
+  NotifyCategoryDecl(egldisplay, EXPCL_PANDAGLES, EXPTP_PANDAGLES);
+  
+  extern EXPCL_PANDAGLES void init_libegldisplay();
+  extern EXPCL_PANDAGLES const string get_egl_error_string(int error);
+#endif
+
+extern ConfigVariableString display_cfg;
+extern ConfigVariableBool x_error_abort;
+
+extern ConfigVariableInt x_wheel_up_button;
+extern ConfigVariableInt x_wheel_down_button;
+extern ConfigVariableInt x_wheel_left_button;
+extern ConfigVariableInt x_wheel_right_button;
+
+#endif

+ 229 - 0
panda/src/egldisplay/eglGraphicsBuffer.cxx

@@ -0,0 +1,229 @@
+// Filename: eglGraphicsBuffer.cxx
+// Created by:  pro-rsoft (13Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "eglGraphicsBuffer.h"
+#include "eglGraphicsStateGuardian.h"
+#include "config_egldisplay.h"
+#include "eglGraphicsPipe.h"
+
+#include "graphicsPipe.h"
+#include "pStatTimer.h"
+
+TypeHandle eglGraphicsBuffer::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsBuffer::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsBuffer::
+eglGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe, 
+                  const string &name,
+                  const FrameBufferProperties &fb_prop,
+                  const WindowProperties &win_prop,
+                  int flags,
+                  GraphicsStateGuardian *gsg,
+                  GraphicsOutput *host) :
+  GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
+{
+  eglGraphicsPipe *egl_pipe;
+  DCAST_INTO_V(egl_pipe, _pipe);
+  _pbuffer = EGL_NO_SURFACE;
+
+  // Since the pbuffer never gets flipped, we get screenshots from the
+  // same buffer we draw into.
+  _screenshot_buffer_type = _draw_buffer_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsBuffer::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsBuffer::
+~eglGraphicsBuffer() {
+  nassertv(_pbuffer == EGL_NO_SURFACE);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsBuffer::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 eglGraphicsBuffer::
+begin_frame(FrameMode mode, Thread *current_thread) {
+  PStatTimer timer(_make_current_pcollector, current_thread);
+
+  begin_frame_spam(mode);
+  if (_gsg == (GraphicsStateGuardian *)NULL) {
+    return false;
+  }
+
+  eglGraphicsStateGuardian *eglgsg;
+  DCAST_INTO_R(eglgsg, _gsg, false);
+  if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
+    egldisplay_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.)
+  eglgsg->reset_if_new();
+
+  if (mode == FM_render) {
+    for (int i=0; i<count_textures(); i++) {
+      if (get_rtm_mode(i) == RTM_bind_or_copy) {
+        _textures[i]._rtm_mode = RTM_copy_texture;
+      }
+    }
+    clear_cube_map_selection();
+  }
+  
+  _gsg->set_current_properties(&get_fb_properties());
+  return _gsg->begin_frame(current_thread);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsBuffer::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 eglGraphicsBuffer::
+end_frame(FrameMode mode, Thread *current_thread) {
+  end_frame_spam(mode);
+  nassertv(_gsg != (GraphicsStateGuardian *)NULL);
+
+  if (mode == FM_render) {
+    copy_to_textures();
+  }
+
+  _gsg->end_frame(current_thread);
+
+  if (mode == FM_render) {
+    trigger_flip();
+    if (_one_shot) {
+      prepare_for_deletion();
+    }
+    clear_cube_map_selection();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsBuffer::close_buffer
+//       Access: Protected, Virtual
+//  Description: Closes the buffer right now.  Called from the window
+//               thread.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsBuffer::
+close_buffer() {
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+    eglGraphicsStateGuardian *eglgsg;
+    DCAST_INTO_V(eglgsg, _gsg);
+    if (!eglMakeCurrent(eglgsg->_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+      egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
+        << get_egl_error_string(eglGetError()) << "\n";
+    }
+    _gsg.clear();
+    _active = false;
+    
+    if (_pbuffer != EGL_NO_SURFACE) {
+      if (!eglDestroySurface(_egl_display, _pbuffer)) {
+        egldisplay_cat.error() << "Failed to destroy surface: "
+          << get_egl_error_string(eglGetError()) << "\n";
+      }
+      _pbuffer = EGL_NO_SURFACE;
+    }
+  }
+
+  _is_valid = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsBuffer::open_buffer
+//       Access: Protected, Virtual
+//  Description: Opens the buffer right now.  Called from the window
+//               thread.  Returns true if the buffer is successfully
+//               opened, or false if there was a problem.
+////////////////////////////////////////////////////////////////////
+bool eglGraphicsBuffer::
+open_buffer() {
+  eglGraphicsPipe *egl_pipe;
+  DCAST_INTO_R(egl_pipe, _pipe, false);
+
+  // GSG Creation/Initialization
+  eglGraphicsStateGuardian *eglgsg;
+  if (_gsg == 0) {
+    // There is no old gsg.  Create a new one.
+    eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL);
+    eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false);
+    _gsg = eglgsg;
+  } else {
+    // If the old gsg has the wrong pixel format, create a
+    // new one that shares with the old gsg.
+    DCAST_INTO_R(eglgsg, _gsg, false);
+    if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
+      eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
+      eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false);
+      _gsg = eglgsg;
+    }
+  }
+  
+  if (eglgsg->_fbconfig == None) {
+    // If we didn't use an fbconfig to create the GSG, we can't create
+    // a PBuffer.
+    return false;
+  }
+
+  int attrib_list[] = {
+    EGL_WIDTH, _x_size,
+    EGL_HEIGHT, _y_size,
+    EGL_NONE
+  };
+  
+  _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list);
+
+  if (_pbuffer == EGL_NO_SURFACE) {
+    egldisplay_cat.error()
+      << "Failed to create EGL pbuffer surface: "
+      << get_egl_error_string(eglGetError()) << "\n";
+    return false;
+  }
+
+  if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
+    egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
+      << get_egl_error_string(eglGetError()) << "\n";
+  }
+  eglgsg->reset_if_new();
+  if (!eglgsg->is_valid()) {
+    close_buffer();
+    return false;
+  }
+  if (!eglgsg->get_fb_properties().verify_hardware_software
+      (_fb_properties, eglgsg->get_gl_renderer())) {
+    close_buffer();
+    return false;
+  }
+  _fb_properties = eglgsg->get_fb_properties();
+  
+  _is_valid = true;
+  return true;
+}

+ 69 - 0
panda/src/egldisplay/eglGraphicsBuffer.h

@@ -0,0 +1,69 @@
+// Filename: eglGraphicsBuffer.h
+// Created by:  pro-rsoft (13Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 EGLGRAPHICSBUFFER_H
+#define EGLGRAPHICSBUFFER_H
+
+#include "pandabase.h"
+
+#include "eglGraphicsPipe.h"
+#include "graphicsBuffer.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : eglGraphicsBuffer
+// Description : An offscreen buffer in the EGL environment.  This
+//               creates an EGL pbuffer.
+////////////////////////////////////////////////////////////////////
+class eglGraphicsBuffer : public GraphicsBuffer {
+public:
+  eglGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe, 
+                    const string &name,
+                    const FrameBufferProperties &fb_prop,
+                    const WindowProperties &win_prop,
+                    int flags,
+                    GraphicsStateGuardian *gsg,
+                    GraphicsOutput *host);
+  virtual ~eglGraphicsBuffer();
+
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
+
+protected:
+  virtual void close_buffer();
+  virtual bool open_buffer();
+
+private:
+  Display *_display;
+  EGLSurface _pbuffer;
+  EGLDisplay _egl_display;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    GraphicsBuffer::init_type();
+    register_type(_type_handle, "eglGraphicsBuffer",
+                  GraphicsBuffer::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;
+};
+
+#endif

+ 72 - 0
panda/src/egldisplay/eglGraphicsPipe.I

@@ -0,0 +1,72 @@
+// Filename: eglGraphicsPipe.I
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::get_display
+//       Access: Public
+//  Description: Returns a pointer to the X display associated with
+//               the pipe: the display on which to create the windows.
+////////////////////////////////////////////////////////////////////
+INLINE Display *eglGraphicsPipe::
+get_display() const {
+  return _display;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::get_screen
+//       Access: Public
+//  Description: Returns the X screen number associated with the pipe.
+////////////////////////////////////////////////////////////////////
+INLINE int eglGraphicsPipe::
+get_screen() const {
+  return _screen;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::get_root
+//       Access: Public
+//  Description: Returns the handle to the root window on the pipe's
+//               display.
+////////////////////////////////////////////////////////////////////
+INLINE Window eglGraphicsPipe::
+get_root() const {
+  return _root;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::get_im
+//       Access: Public
+//  Description: Returns the input method opened for the pipe, or NULL
+//               if the input method could not be opened for some
+//               reason.
+////////////////////////////////////////////////////////////////////
+INLINE XIM eglGraphicsPipe::
+get_im() const {
+  return _im;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::get_hidden_cursor
+//       Access: Public
+//  Description: Returns an invisible Cursor suitable for assigning to
+//               windows that have the cursor_hidden property set.
+////////////////////////////////////////////////////////////////////
+INLINE Cursor eglGraphicsPipe::
+get_hidden_cursor() {
+  if (_hidden_cursor == None) {
+    make_hidden_cursor();
+  }
+  return _hidden_cursor;
+}

+ 429 - 0
panda/src/egldisplay/eglGraphicsPipe.cxx

@@ -0,0 +1,429 @@
+// Filename: eglGraphicsPipe.cxx
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "eglGraphicsBuffer.h"
+#include "eglGraphicsPipe.h"
+#include "eglGraphicsPixmap.h"
+#include "eglGraphicsWindow.h"
+#include "eglGraphicsStateGuardian.h"
+#include "config_egldisplay.h"
+#include "frameBufferProperties.h"
+
+TypeHandle eglGraphicsPipe::_type_handle;
+
+bool eglGraphicsPipe::_error_handlers_installed = false;
+eglGraphicsPipe::ErrorHandlerFunc *eglGraphicsPipe::_prev_error_handler;
+eglGraphicsPipe::IOErrorHandlerFunc *eglGraphicsPipe::_prev_io_error_handler;
+
+LightReMutex eglGraphicsPipe::_x_mutex;
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsPipe::
+eglGraphicsPipe(const string &display) {
+  string display_spec = display;
+  if (display_spec.empty()) {
+    display_spec = display_cfg;
+  }
+  if (display_spec.empty()) {
+    display_spec = ExecutionEnvironment::get_environment_variable("DISPLAY");
+  }
+  if (display_spec.empty()) {
+    display_spec = ":0.0";
+  }
+
+  // The X docs say we should do this to get international character
+  // support from the keyboard.
+  setlocale(LC_ALL, "");
+
+  // But it's important that we use the "C" locale for numeric
+  // formatting, since all of the internal Panda code assumes this--we
+  // need a decimal point to mean a decimal point.
+  setlocale(LC_NUMERIC, "C");
+
+  _is_valid = false;
+  _supported_types = OT_window | OT_buffer | OT_texture_buffer;
+  _display = NULL;
+  _screen = 0;
+  _root = (Window)NULL;
+  _im = (XIM)NULL;
+  _hidden_cursor = None;
+  _egl_display = NULL;
+
+  install_error_handlers();
+
+  _display = XOpenDisplay(display_spec.c_str());
+  if (!_display) {
+    egldisplay_cat.error()
+      << "Could not open display \"" << display_spec << "\".\n";
+    return;
+  }
+
+  if (!XSupportsLocale()) {
+    egldisplay_cat.warning()
+      << "X does not support locale " << setlocale(LC_ALL, NULL) << "\n";
+  }
+  XSetLocaleModifiers("");
+
+  _screen = DefaultScreen(_display);
+  _root = RootWindow(_display, _screen);
+  _display_width = DisplayWidth(_display, _screen);
+  _display_height = DisplayHeight(_display, _screen);
+  _is_valid = true;
+
+  _egl_display = eglGetDisplay((NativeDisplayType) _display);
+  if (!eglInitialize(_egl_display, NULL, NULL)) {
+    egldisplay_cat.error()
+      << "Couldn't initialize the EGL display: "
+      << get_egl_error_string(eglGetError()) << "\n";
+  }
+
+  // Connect to an input method for supporting international text
+  // entry.
+  _im = XOpenIM(_display, NULL, NULL, NULL);
+  if (_im == (XIM)NULL) {
+    egldisplay_cat.warning()
+      << "Couldn't open input method.\n";
+  }
+
+  // What styles does the current input method support?
+  /*
+  XIMStyles *im_supported_styles;
+  XGetIMValues(_im, XNQueryInputStyle, &im_supported_styles, NULL);
+
+  for (int i = 0; i < im_supported_styles->count_styles; i++) {
+    XIMStyle style = im_supported_styles->supported_styles[i];
+    cerr << "style " << i << ". " << hex << style << dec << "\n";
+  }
+
+  XFree(im_supported_styles);
+  */
+
+  // Get some X atom numbers.
+  _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", false);
+  _net_wm_window_type = XInternAtom(_display, "_NET_WM_WINDOW_TYPE", false);
+  _net_wm_window_type_splash = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_SPLASH", false);
+  _net_wm_window_type_fullscreen = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_FULLSCREEN", false);
+  _net_wm_state = XInternAtom(_display, "_NET_WM_STATE", false);
+  _net_wm_state_fullscreen = XInternAtom(_display, "_NET_WM_STATE_FULLSCREEN", false);
+  _net_wm_state_above = XInternAtom(_display, "_NET_WM_STATE_ABOVE", false);
+  _net_wm_state_below = XInternAtom(_display, "_NET_WM_STATE_BELOW", false);
+  _net_wm_state_add = XInternAtom(_display, "_NET_WM_STATE_ADD", false);
+  _net_wm_state_remove = XInternAtom(_display, "_NET_WM_STATE_REMOVE", false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsPipe::
+~eglGraphicsPipe() {
+  release_hidden_cursor();
+  if (_im) {
+    XCloseIM(_im);
+  }
+  if (_display) {
+    XCloseDisplay(_display);
+  }
+  if (_egl_display) {
+    if (!eglTerminate(_egl_display)) {
+      egldisplay_cat.error() << "Failed to terminate EGL display: "
+        << get_egl_error_string(eglGetError()) << "\n";
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::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 eglGraphicsPipe::
+get_interface_name() const {
+  return "OpenGL ES";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::pipe_constructor
+//       Access: Public, Static
+//  Description: This function is passed to the GraphicsPipeSelection
+//               object to allow the user to make a default
+//               eglGraphicsPipe.
+////////////////////////////////////////////////////////////////////
+PT(GraphicsPipe) eglGraphicsPipe::
+pipe_constructor() {
+  return new eglGraphicsPipe;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::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
+eglGraphicsPipe::get_preferred_window_thread() const {
+  // Actually, since we're creating the graphics context in
+  // open_window() now, it appears we need to ensure the open_window()
+  // call is performed in the draw thread for now, even though X wants
+  // all of its calls to be single-threaded.
+
+  // This means that all X windows may have to be handled by the same
+  // draw thread, which we didn't intend (though the global _x_mutex
+  // may allow them to be technically served by different threads,
+  // even though the actual X calls will be serialized).  There might
+  // be a better way.
+
+  return PWT_draw;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::make_output
+//       Access: Protected, Virtual
+//  Description: Creates a new window on the pipe, if possible.
+////////////////////////////////////////////////////////////////////
+PT(GraphicsOutput) eglGraphicsPipe::
+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;
+  }
+
+  eglGraphicsStateGuardian *eglgsg = 0;
+  if (gsg != 0) {
+    DCAST_INTO_R(eglgsg, gsg, NULL);
+  }
+
+  bool support_rtt;
+  support_rtt = false;
+  if (eglgsg) {
+     support_rtt =
+      eglgsg -> get_supports_render_texture() &&
+      support_render_texture;
+  }
+  // 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 eglGraphicsWindow(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);
+  }
+
+  // Third 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;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::make_hidden_cursor
+//       Access: Private
+//  Description: Called once to make an invisible Cursor for return
+//               from get_hidden_cursor().
+////////////////////////////////////////////////////////////////////
+void eglGraphicsPipe::
+make_hidden_cursor() {
+  nassertv(_hidden_cursor == None);
+
+  unsigned int x_size, y_size;
+  XQueryBestCursor(_display, _root, 1, 1, &x_size, &y_size);
+
+  Pixmap empty = XCreatePixmap(_display, _root, x_size, y_size, 1);
+
+  XColor black;
+  memset(&black, 0, sizeof(black));
+
+  _hidden_cursor = XCreatePixmapCursor(_display, empty, empty,
+                                       &black, &black, x_size, y_size);
+  XFreePixmap(_display, empty);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::release_hidden_cursor
+//       Access: Private
+//  Description: Called once to release the invisible cursor created
+//               by make_hidden_cursor().
+////////////////////////////////////////////////////////////////////
+void eglGraphicsPipe::
+release_hidden_cursor() {
+  if (_hidden_cursor != None) {
+    XFreeCursor(_display, _hidden_cursor);
+    _hidden_cursor = None;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::install_error_handlers
+//       Access: Private, Static
+//  Description: Installs new Xlib error handler functions if this is
+//               the first time this function has been called.  These
+//               error handler functions will attempt to reduce Xlib's
+//               annoying tendency to shut down the client at the
+//               first error.  Unfortunately, it is difficult to play
+//               nice with the client if it has already installed its
+//               own error handlers.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsPipe::
+install_error_handlers() {
+  if (_error_handlers_installed) {
+    return;
+  }
+
+  _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler);
+  _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler);
+  _error_handlers_installed = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::error_handler
+//       Access: Private, Static
+//  Description: This function is installed as the error handler for a
+//               non-fatal Xlib error.
+////////////////////////////////////////////////////////////////////
+int eglGraphicsPipe::
+error_handler(Display *display, XErrorEvent *error) {
+  static const int msg_len = 80;
+  char msg[msg_len];
+  XGetErrorText(display, error->error_code, msg, msg_len);
+  egldisplay_cat.error()
+    << msg << "\n";
+
+  if (x_error_abort) {
+    abort();
+  }
+
+  // We return to allow the application to continue running, unlike
+  // the default X error handler which exits.
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPipe::io_error_handler
+//       Access: Private, Static
+//  Description: This function is installed as the error handler for a
+//               fatal Xlib error.
+////////////////////////////////////////////////////////////////////
+int eglGraphicsPipe::
+io_error_handler(Display *display) {
+  egldisplay_cat.fatal()
+    << "X fatal error on display " << (void *)display << "\n";
+
+  // Unfortunately, we can't continue from this function, even if we
+  // promise never to use X again.  We're supposed to terminate
+  // without returning, and if we do return, the caller will exit
+  // anyway.  Sigh.  Very poor design on X's part.
+  return 0;
+}

+ 155 - 0
panda/src/egldisplay/eglGraphicsPipe.h

@@ -0,0 +1,155 @@
+// Filename: eglGraphicsPipe.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 EGLGRAPHICSPIPE_H
+#define EGLGRAPHICSPIPE_H
+
+#include "pandabase.h"
+#include "graphicsWindow.h"
+#include "graphicsPipe.h"
+#include "lightMutex.h"
+#include "lightReMutex.h"
+
+#ifdef OPENGLES_2
+  #include "gles2gsg.h"
+  #include <EGL/egl.h>
+  #define NativeDisplayType EGLNativeDisplayType
+  #define NativePixmapType EGLNativePixmapType
+  #define NativeWindowType EGLNativeWindowType
+#else
+  #include "glesgsg.h"
+  #include <GLES/egl.h>
+#endif
+
+class FrameBufferProperties;
+
+#ifdef CPPPARSER
+// A simple hack so interrogate can parse this file.
+typedef int Display;
+typedef int Window;
+typedef int XErrorEvent;
+typedef int XVisualInfo;
+typedef int Atom;
+typedef int Cursor;
+typedef int XIM;
+typedef int XIC;
+#else
+#include <X11/Xlib.h>
+
+#endif  // CPPPARSER
+
+class eglGraphicsBuffer;
+class eglGraphicsPixmap;
+class eglGraphicsWindow;
+
+////////////////////////////////////////////////////////////////////
+//       Class : eglGraphicsPipe
+// Description : This graphics pipe represents the interface for
+//               creating OpenGL ES graphics windows on an X-based
+//               (e.g. Unix) client.
+////////////////////////////////////////////////////////////////////
+class eglGraphicsPipe : public GraphicsPipe {
+public:
+  eglGraphicsPipe(const string &display = string());
+  virtual ~eglGraphicsPipe();
+
+  virtual string get_interface_name() const;
+  static PT(GraphicsPipe) pipe_constructor();
+
+  INLINE Display *get_display() const;
+  INLINE int get_screen() const;
+  INLINE Window get_root() const;
+  INLINE XIM get_im() const;
+
+  INLINE Cursor get_hidden_cursor();
+
+public:
+  virtual PreferredWindowThread get_preferred_window_thread() const;
+
+public:
+  // Atom specifications.
+  Atom _wm_delete_window;
+  Atom _net_wm_window_type;
+  Atom _net_wm_window_type_splash;
+  Atom _net_wm_window_type_fullscreen;
+  Atom _net_wm_state;
+  Atom _net_wm_state_fullscreen;
+  Atom _net_wm_state_above;
+  Atom _net_wm_state_below;
+  Atom _net_wm_state_add;
+  Atom _net_wm_state_remove;
+
+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:
+  void make_hidden_cursor();
+  void release_hidden_cursor();
+
+  static void install_error_handlers();
+  static int error_handler(Display *display, XErrorEvent *error);
+  static int io_error_handler(Display *display);
+
+  Display *_display;
+  int _screen;
+  Window _root;
+  XIM _im;
+  EGLDisplay _egl_display;
+
+  Cursor _hidden_cursor;
+
+  typedef int ErrorHandlerFunc(Display *, XErrorEvent *);
+  typedef int IOErrorHandlerFunc(Display *);
+  static bool _error_handlers_installed;
+  static ErrorHandlerFunc *_prev_error_handler;
+  static IOErrorHandlerFunc *_prev_io_error_handler;
+
+public:
+  // This Mutex protects any X library calls, which all have to be
+  // single-threaded.  In particular, it protects eglMakeCurrent().
+  static LightReMutex _x_mutex;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    GraphicsPipe::init_type();
+    register_type(_type_handle, "eglGraphicsPipe",
+                  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 eglGraphicsBuffer;
+  friend class eglGraphicsPixmap;
+  friend class eglGraphicsWindow;
+};
+
+#include "eglGraphicsPipe.I"
+
+#endif

+ 258 - 0
panda/src/egldisplay/eglGraphicsPixmap.cxx

@@ -0,0 +1,258 @@
+// Filename: eglGraphicsPixmap.cxx
+// Created by:  pro-rsoft (13Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "eglGraphicsPixmap.h"
+#include "eglGraphicsWindow.h"
+#include "eglGraphicsStateGuardian.h"
+#include "config_egldisplay.h"
+#include "eglGraphicsPipe.h"
+
+#include "graphicsPipe.h"
+#include "pStatTimer.h"
+
+TypeHandle eglGraphicsPixmap::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPixmap::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsPixmap::
+eglGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe, 
+                  const string &name,
+                  const FrameBufferProperties &fb_prop,
+                  const WindowProperties &win_prop,
+                  int flags,
+                  GraphicsStateGuardian *gsg,
+                  GraphicsOutput *host) :
+  GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
+{
+  eglGraphicsPipe *egl_pipe;
+  DCAST_INTO_V(egl_pipe, _pipe);
+  _display = egl_pipe->get_display();
+  _egl_display = egl_pipe->_egl_display;
+  _drawable = None;
+  _x_pixmap = None;
+  _egl_surface = EGL_NO_SURFACE;
+
+  // Since the pixmap never gets flipped, we get screenshots from the
+  // same pixmap we draw into.
+  _screenshot_buffer_type = _draw_buffer_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPixmap::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsPixmap::
+~eglGraphicsPixmap() {
+  nassertv(_x_pixmap == None && _egl_surface == EGL_NO_SURFACE);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPixmap::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 eglGraphicsPixmap::
+begin_frame(FrameMode mode, Thread *current_thread) {
+  PStatTimer timer(_make_current_pcollector, current_thread);
+
+  begin_frame_spam(mode);
+  if (_gsg == (GraphicsStateGuardian *)NULL) {
+    return false;
+  }
+
+  eglGraphicsStateGuardian *eglgsg;
+  DCAST_INTO_R(eglgsg, _gsg, false);
+  if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context)) {
+    egldisplay_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.)
+  eglgsg->reset_if_new();
+
+  if (mode == FM_render) {
+    for (int i=0; i<count_textures(); i++) {
+      if (get_rtm_mode(i) == RTM_bind_or_copy) {
+        _textures[i]._rtm_mode = RTM_copy_texture;
+      }
+    }
+    clear_cube_map_selection();
+  }
+  
+  _gsg->set_current_properties(&get_fb_properties());
+  return _gsg->begin_frame(current_thread);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPixmap::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 eglGraphicsPixmap::
+end_frame(FrameMode mode, Thread *current_thread) {
+  end_frame_spam(mode);
+  nassertv(_gsg != (GraphicsStateGuardian *)NULL);
+
+  if (mode == FM_render) {
+    copy_to_textures();
+  }
+
+  _gsg->end_frame(current_thread);
+
+  if (mode == FM_render) {
+    trigger_flip();
+    if (_one_shot) {
+      prepare_for_deletion();
+    }
+    clear_cube_map_selection();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPixmap::close_buffer
+//       Access: Protected, Virtual
+//  Description: Closes the pixmap right now.  Called from the window
+//               thread.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsPixmap::
+close_buffer() {
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+    if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+      egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
+        << get_egl_error_string(eglGetError()) << "\n";
+    }
+    _gsg.clear();
+    _active = false;
+  }
+
+  if (_egl_surface != EGL_NO_SURFACE) {
+    if (!eglDestroySurface(_egl_display, _egl_surface)) {
+      egldisplay_cat.error() << "Failed to destroy surface: "
+        << get_egl_error_string(eglGetError()) << "\n";
+    }
+    _egl_surface = EGL_NO_SURFACE;
+  }
+
+  if (_x_pixmap != None) {
+    XFreePixmap(_display, _x_pixmap);
+    _x_pixmap = None;
+  }
+
+  _is_valid = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsPixmap::open_buffer
+//       Access: Protected, Virtual
+//  Description: Opens the pixmap right now.  Called from the window
+//               thread.  Returns true if the pixmap is successfully
+//               opened, or false if there was a problem.
+////////////////////////////////////////////////////////////////////
+bool eglGraphicsPixmap::
+open_buffer() {
+  eglGraphicsPipe *egl_pipe;
+  DCAST_INTO_R(egl_pipe, _pipe, false);
+
+  // GSG Creation/Initialization
+  eglGraphicsStateGuardian *eglgsg;
+  if (_gsg == 0) {
+    // There is no old gsg.  Create a new one.
+    eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL);
+    eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true);
+    _gsg = eglgsg;
+  } else {
+    // If the old gsg has the wrong pixel format, create a
+    // new one that shares with the old gsg.
+    DCAST_INTO_R(eglgsg, _gsg, false);
+    if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
+      eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
+      eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true);
+      _gsg = eglgsg;
+    }
+  }
+  
+  if (eglgsg->_fbconfig == None) {
+    // If we didn't use an fbconfig to create the GSG, we can't create
+    // a PBuffer.
+    return false;
+  }
+
+  XVisualInfo *visual_info = eglgsg->_visual;
+  if (visual_info == NULL) {
+    // No X visual for this fbconfig; how can we create the pixmap?
+    egldisplay_cat.error()
+      << "No X visual: cannot create pixmap.\n";
+    return false;
+  }
+
+  _drawable = egl_pipe->get_root();
+  if (_host != NULL) {
+    if (_host->is_of_type(eglGraphicsWindow::get_class_type())) {
+      eglGraphicsWindow *win = DCAST(eglGraphicsWindow, _host);
+      _drawable = win->get_xwindow();
+    } else if (_host->is_of_type(eglGraphicsPixmap::get_class_type())) {
+      eglGraphicsPixmap *pix = DCAST(eglGraphicsPixmap, _host);
+      _drawable = pix->_drawable;
+    }
+  }
+
+  _x_pixmap = XCreatePixmap(_display, _drawable, 
+                            _x_size, _y_size, visual_info->depth);
+  if (_x_pixmap == None) {
+    egldisplay_cat.error()
+      << "Failed to create X pixmap.\n";
+    close_buffer();
+    return false;
+  }
+
+  nassertr(eglgsg->_fbconfig, false);
+  _egl_surface = eglCreatePixmapSurface(_egl_display, eglgsg->_fbconfig, (NativePixmapType) _x_pixmap, NULL);
+
+  if (_egl_surface == EGL_NO_SURFACE) {
+    egldisplay_cat.error()
+      << "Failed to create EGL pixmap surface:"
+      << get_egl_error_string(eglGetError()) << "\n";
+    close_buffer();
+    return false;
+  }
+
+  eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context);
+  eglgsg->reset_if_new();
+  if (!eglgsg->is_valid()) {
+    close_buffer();
+    return false;
+  }
+  if (!eglgsg->get_fb_properties().verify_hardware_software
+      (_fb_properties, eglgsg->get_gl_renderer())) {
+    close_buffer();
+    return false;
+  }
+  _fb_properties = eglgsg->get_fb_properties();
+  
+  _is_valid = true;
+  return true;
+}

+ 73 - 0
panda/src/egldisplay/eglGraphicsPixmap.h

@@ -0,0 +1,73 @@
+// Filename: eglGraphicsPixmap.h
+// Created by:  pro-rsoft (13Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 EGLGRAPHICSPIXMAP_H
+#define EGLGRAPHICSPIXMAP_H
+
+#include "pandabase.h"
+
+#include "eglGraphicsPipe.h"
+#include "graphicsBuffer.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : eglGraphicsPixmap
+// Description : Another offscreen buffer in the EGL environment.  This
+//               creates a Pixmap object, which is probably less
+//               efficient than an EGLPBuffer, so this class is a
+//               second choice to eglGraphicsBuffer.
+////////////////////////////////////////////////////////////////////
+class eglGraphicsPixmap : public GraphicsBuffer {
+public:
+  eglGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe, 
+                    const string &name,
+                    const FrameBufferProperties &fb_prop,
+                    const WindowProperties &win_prop,
+                    int flags,
+                    GraphicsStateGuardian *gsg,
+                    GraphicsOutput *host);
+  virtual ~eglGraphicsPixmap();
+
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
+
+protected:
+  virtual void close_buffer();
+  virtual bool open_buffer();
+
+private:
+  Display *_display;
+  Window _drawable;
+  Pixmap _x_pixmap;
+  EGLSurface _egl_surface;
+  EGLDisplay _egl_display;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    GraphicsBuffer::init_type();
+    register_type(_type_handle, "eglGraphicsPixmap",
+                  GraphicsBuffer::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;
+};
+
+#endif

+ 26 - 0
panda/src/egldisplay/eglGraphicsStateGuardian.I

@@ -0,0 +1,26 @@
+// Filename: eglGraphicsStateGuardian.I
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsStateGuardian::get_fb_properties
+//       Access: Private
+//  Description: Gets the FrameBufferProperties for all windows and
+//               buffers that use this GSG.
+////////////////////////////////////////////////////////////////////
+INLINE const FrameBufferProperties &eglGraphicsStateGuardian::
+get_fb_properties() const {
+  return _fbprops;
+}
+
+

+ 376 - 0
panda/src/egldisplay/eglGraphicsStateGuardian.cxx

@@ -0,0 +1,376 @@
+// Filename: eglGraphicsStateGuardian.cxx
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "eglGraphicsStateGuardian.h"
+#include "config_egldisplay.h"
+#include "lightReMutexHolder.h"
+
+#include <dlfcn.h>
+
+TypeHandle eglGraphicsStateGuardian::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsStateGuardian::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsStateGuardian::
+eglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
+       eglGraphicsStateGuardian *share_with) :
+#ifdef OPENGLES_2
+  GLES2GraphicsStateGuardian(engine, pipe)
+#else
+  GLESGraphicsStateGuardian(engine, pipe)
+#endif
+{
+  _share_context=0;
+  _context=0;
+  _display=0;
+  _egl_display=0;
+  _screen=0;
+  _visual=0;
+  _visuals=0;
+  _fbconfig=0;
+
+  if (share_with != (eglGraphicsStateGuardian *)NULL) {
+    _prepared_objects = share_with->get_prepared_objects();
+    _share_context = share_with->_context;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsStateGuardian::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsStateGuardian::
+~eglGraphicsStateGuardian() {
+  if (_visuals != (XVisualInfo *)NULL) {
+    XFree(_visuals);
+  }
+  if (_context != (EGLContext)NULL) {
+    if (!eglDestroyContext(_egl_display, _context)) {
+      egldisplay_cat.error() << "Failed to destroy EGL context: "
+        << get_egl_error_string(eglGetError()) << "\n";
+    }
+    _context = (EGLContext)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsStateGuardian::get_properties
+//       Access: Private
+//  Description: Gets the FrameBufferProperties to match the
+//               indicated config.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsStateGuardian::
+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.
+  int 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) {
+    egldisplay_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: eglGraphicsStateGuardian::choose_pixel_format
+//       Access: Private
+//  Description: Selects a visual or fbconfig for all the windows
+//               and buffers that use this gsg.  Also creates the GL
+//               context and obtains the visual.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsStateGuardian::
+choose_pixel_format(const FrameBufferProperties &properties,
+        Display *display,
+        int screen, bool need_pbuffer, bool need_pixmap) {
+
+  _display = display;
+  _egl_display = eglGetDisplay((NativeDisplayType) display);
+  _screen = screen;
+  _context = 0;
+  _fbconfig = 0;
+  _visual = 0;
+  _visuals = 0;
+  _fbprops.clear();
+
+  int attrib_list[] = {
+    EGL_RENDERABLE_TYPE, EGL_DONT_CARE,
+    EGL_SURFACE_TYPE, EGL_DONT_CARE,
+    EGL_NONE
+  };
+
+  int num_configs = 0;
+  EGLConfig configs[32];
+  if (!eglChooseConfig(_egl_display, attrib_list, configs, 32, &num_configs) || num_configs <= 0) {
+    egldisplay_cat.error() << "eglChooseConfig failed: "
+      << get_egl_error_string(eglGetError()) << "\n";
+    return;
+  }
+
+  int best_quality = 0;
+  int best_result = 0;
+  FrameBufferProperties best_props;
+
+  if (configs != 0) {
+    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)" : "";
+      egldisplay_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;
+      }
+    }
+  }
+  int depth = DefaultDepth(_display, _screen);
+  _visual = new XVisualInfo;
+  XMatchVisualInfo(_display, _screen, depth, TrueColor, _visual);
+
+  if (best_quality > 0) {
+    egldisplay_cat.debug()
+      << "Chosen config " << best_result << ": " << best_props << "\n";
+    _fbconfig = configs[best_result];
+    _context = eglCreateContext(_egl_display, _fbconfig, _share_context, NULL);
+    int err = eglGetError();
+    if (_context && err == EGL_SUCCESS) {
+      if (_visual) {
+        _fbprops = best_props;
+        return;
+      }
+    }
+    // This really shouldn't happen, so I'm not too careful about cleanup.
+    egldisplay_cat.error()
+      << "Could not create EGL context!\n"
+      << get_egl_error_string(err) << "\n";
+    _fbconfig = 0;
+    _context = 0;
+    _visual = 0;
+    _visuals = 0;
+  }
+
+  egldisplay_cat.error() <<
+    "Could not find a usable pixel format.\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsStateGuardian::reset
+//       Access: Public, Virtual
+//  Description: Resets all internal state as if the gsg were newly
+//               created.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsStateGuardian::
+reset() {
+#ifdef OPENGLES_2
+  GLES2GraphicsStateGuardian::reset();
+#else
+  GLESGraphicsStateGuardian::reset();
+#endif
+
+  // If "Mesa" is present, assume software.  However, if "Mesa DRI" is
+  // found, it's actually a Mesa-based OpenGL layer running over a
+  // hardware driver.
+  if (_gl_renderer.find("Mesa") != string::npos &&
+      _gl_renderer.find("Mesa DRI") == string::npos) {
+    // It's Mesa, therefore probably a software context.
+    _fbprops.set_force_software(1);
+    _fbprops.set_force_hardware(0);
+  } else {
+    _fbprops.set_force_hardware(1);
+    _fbprops.set_force_software(0);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsStateGuardian::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 eglGraphicsStateGuardian::
+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: eglGraphicsStateGuardian::gl_flush
+//       Access: Protected, Virtual
+//  Description: Calls glFlush().
+////////////////////////////////////////////////////////////////////
+void eglGraphicsStateGuardian::
+gl_flush() const {
+  // This call requires synchronization with X.
+  LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
+#ifdef OPENGLES_2
+  GLES2GraphicsStateGuardian::gl_flush();
+#else
+  GLESGraphicsStateGuardian::gl_flush();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsStateGuardian::gl_get_error
+//       Access: Protected, Virtual
+//  Description: Returns the result of glGetError().
+////////////////////////////////////////////////////////////////////
+GLenum eglGraphicsStateGuardian::
+gl_get_error() const {
+  // This call requires synchronization with X.
+  LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
+#ifdef OPENGLES_2
+  return GLES2GraphicsStateGuardian::gl_get_error();
+#else
+  return GLESGraphicsStateGuardian::gl_get_error();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsStateGuardian::query_gl_version
+//       Access: Protected, Virtual
+//  Description: Queries the runtime version of OpenGL in use.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsStateGuardian::
+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)) {
+    egldisplay_cat.error() << "Failed to get EGL version number: "
+      << get_egl_error_string(eglGetError()) << "\n";
+  }
+
+  // We output to glesgsg_cat instead of egldisplay_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: eglGraphicsStateGuardian::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 eglGraphicsStateGuardian::
+get_extra_extensions() {
+  save_extensions(eglQueryString(_egl_display, EGL_EXTENSIONS));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsStateGuardian::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 *eglGraphicsStateGuardian::
+do_get_extension_func(const char *prefix, const char *name) {
+  string fullname = string(prefix) + string(name);
+
+  return (void *)eglGetProcAddress(fullname.c_str());
+}

+ 99 - 0
panda/src/egldisplay/eglGraphicsStateGuardian.h

@@ -0,0 +1,99 @@
+// Filename: eglGraphicsStateGuardian.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 EGLGRAPHICSSTATEGUARDIAN_H
+#define EGLGRAPHICSSTATEGUARDIAN_H
+
+#include "pandabase.h"
+#include "eglGraphicsPipe.h"
+
+#include <X11/Xutil.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : eglGraphicsStateGuardian
+// Description : A tiny specialization on GLESGraphicsStateGuardian
+//               to add some egl-specific information.
+////////////////////////////////////////////////////////////////////
+#ifdef OPENGLES_2
+class eglGraphicsStateGuardian : public GLES2GraphicsStateGuardian {
+#else
+class eglGraphicsStateGuardian : 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,
+         Display *_display,
+         int _screen,
+         bool need_pbuffer, bool need_pixmap);
+
+  eglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
+         eglGraphicsStateGuardian *share_with);
+
+  virtual ~eglGraphicsStateGuardian();
+
+  virtual void reset();
+
+  bool egl_is_at_least_version(int major_version, int minor_version) const;
+
+  EGLContext _share_context;
+  EGLContext _context;
+  EGLDisplay _egl_display;
+  Display *_display;
+  int _screen;
+  XVisualInfo *_visual;
+  XVisualInfo *_visuals;
+  EGLConfig _fbconfig;
+  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;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+#ifdef OPENGLES_2
+    GLES2GraphicsStateGuardian::init_type();
+    register_type(_type_handle, "eglGraphicsStateGuardian",
+                  GLES2GraphicsStateGuardian::get_class_type());
+#else
+    GLESGraphicsStateGuardian::init_type();
+    register_type(_type_handle, "eglGraphicsStateGuardian",
+                  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 "eglGraphicsStateGuardian.I"
+
+#endif

+ 24 - 0
panda/src/egldisplay/eglGraphicsWindow.I

@@ -0,0 +1,24 @@
+// Filename: eglGraphicsWindow.I
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::get_xwindow
+//       Access: Public
+//  Description: Returns the X11 Window handle.
+////////////////////////////////////////////////////////////////////
+INLINE Window eglGraphicsWindow::
+get_xwindow() const {
+  return _xwindow;
+}

+ 1684 - 0
panda/src/egldisplay/eglGraphicsWindow.cxx

@@ -0,0 +1,1684 @@
+// Filename: eglGraphicsWindow.cxx
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "eglGraphicsWindow.h"
+#include "eglGraphicsStateGuardian.h"
+#include "config_egldisplay.h"
+#include "eglGraphicsPipe.h"
+
+#include "graphicsPipe.h"
+#include "keyboardButton.h"
+#include "mouseButton.h"
+#include "clockObject.h"
+#include "pStatTimer.h"
+#include "textEncoder.h"
+#include "throw_event.h"
+#include "lightReMutexHolder.h"
+
+#include <errno.h>
+#include <sys/time.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+#ifdef HAVE_LINUX_INPUT_H
+#include <linux/input.h>
+#endif
+
+TypeHandle eglGraphicsWindow::_type_handle;
+
+#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)&7)))
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsWindow::
+eglGraphicsWindow(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)
+{
+  eglGraphicsPipe *egl_pipe;
+  DCAST_INTO_V(egl_pipe, _pipe);
+  _display = egl_pipe->get_display();
+  _screen = egl_pipe->get_screen();
+  _xwindow = (Window)NULL;
+  _ic = (XIC)NULL;
+  _egl_display = egl_pipe->_egl_display;
+  _egl_surface = 0;
+  _awaiting_configure = false;
+  _wm_delete_window = egl_pipe->_wm_delete_window;
+  _net_wm_window_type = egl_pipe->_net_wm_window_type;
+  _net_wm_window_type_splash = egl_pipe->_net_wm_window_type_splash;
+  _net_wm_window_type_fullscreen = egl_pipe->_net_wm_window_type_fullscreen;
+  _net_wm_state = egl_pipe->_net_wm_state;
+  _net_wm_state_fullscreen = egl_pipe->_net_wm_state_fullscreen;
+  _net_wm_state_above = egl_pipe->_net_wm_state_above;
+  _net_wm_state_below = egl_pipe->_net_wm_state_below;
+  _net_wm_state_add = egl_pipe->_net_wm_state_add;
+  _net_wm_state_remove = egl_pipe->_net_wm_state_remove;
+
+  GraphicsWindowInputDevice device =
+    GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse");
+  add_input_device(device);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+eglGraphicsWindow::
+~eglGraphicsWindow() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::move_pointer
+//       Access: Published, Virtual
+//  Description: Forces the pointer to the indicated position within
+//               the window, if possible.
+//
+//               Returns true if successful, false on failure.  This
+//               may fail if the mouse is not currently within the
+//               window, or if the API doesn't support this operation.
+////////////////////////////////////////////////////////////////////
+bool eglGraphicsWindow::
+move_pointer(int device, int x, int y) {
+  // Note: this is not thread-safe; it should be called only from App.
+  // Probably not an issue.
+  if (device == 0) {
+    // Move the system mouse pointer.
+    if (!_properties.get_foreground() ||
+        !_input_devices[0].get_pointer().get_in_window()) {
+      // If the window doesn't have input focus, or the mouse isn't
+      // currently within the window, forget it.
+      return false;
+    }
+
+    const MouseData &md = _input_devices[0].get_pointer();
+    if (!md.get_in_window() || md.get_x() != x || md.get_y() != y) {
+      XWarpPointer(_display, None, _xwindow, 0, 0, 0, 0, x, y);
+      _input_devices[0].set_pointer_in_window(x, y);
+    }
+    return true;
+  } else {
+    // Move a raw mouse.
+    if ((device < 1)||(device >= _input_devices.size())) {
+      return false;
+    }
+    _input_devices[device].set_pointer_in_window(x, y);
+    return true;
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::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 eglGraphicsWindow::
+begin_frame(FrameMode mode, Thread *current_thread) {
+  PStatTimer timer(_make_current_pcollector, current_thread);
+
+  begin_frame_spam(mode);
+  if (_gsg == (GraphicsStateGuardian *)NULL) {
+    return false;
+  }
+  if (_awaiting_configure) {
+    // Don't attempt to draw while we have just reconfigured the
+    // window and we haven't got the notification back yet.
+    return false;
+  }
+
+  eglGraphicsStateGuardian *eglgsg;
+  DCAST_INTO_R(eglgsg, _gsg, false);
+  {
+    LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
+
+    if (eglGetCurrentDisplay() == _egl_display &&
+        eglGetCurrentSurface(EGL_READ) == _egl_surface &&
+        eglGetCurrentSurface(EGL_DRAW) == _egl_surface &&
+        eglGetCurrentContext() == eglgsg->_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, eglgsg->_context)) {
+        egldisplay_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.)
+  eglgsg->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: eglGraphicsWindow::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 eglGraphicsWindow::
+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();
+    if (_one_shot) {
+      prepare_for_deletion();
+    }
+    clear_cube_map_selection();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::begin_flip
+//       Access: Public, Virtual
+//  Description: This function will be called within the draw thread
+//               after end_frame() has been called on all windows, to
+//               initiate the exchange of the front and back buffers.
+//
+//               This should instruct the window to prepare for the
+//               flip at the next video sync, but it should not wait.
+//
+//               We have the two separate functions, begin_flip() and
+//               end_flip(), to make it easier to flip all of the
+//               windows at the same time.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsWindow::
+begin_flip() {
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+
+    // 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();
+
+    LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
+    eglSwapBuffers(_egl_display, _egl_surface);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::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 eglGraphicsWindow::
+process_events() {
+  LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
+
+  GraphicsWindow::process_events();
+
+  if (_xwindow == (Window)0) {
+    return;
+  }
+
+  poll_raw_mice();
+
+  XEvent event;
+  XKeyEvent keyrelease_event;
+  bool got_keyrelease_event = false;
+
+  while (XCheckIfEvent(_display, &event, check_event, (char *)this)) {
+    if (XFilterEvent(&event, None)) {
+      continue;
+    }
+
+    if (got_keyrelease_event) {
+      // If a keyrelease event is immediately followed by a matching
+      // keypress event, that's just key repeat and we should treat
+      // the two events accordingly.  It would be nice if X provided a
+      // way to differentiate between keyrepeat and explicit
+      // keypresses more generally.
+      got_keyrelease_event = false;
+
+      if (event.type == KeyPress &&
+          event.xkey.keycode == keyrelease_event.keycode &&
+          (event.xkey.time - keyrelease_event.time <= 1)) {
+        // In particular, we only generate down messages for the
+        // repeated keys, not down-and-up messages.
+        handle_keystroke(event.xkey);
+
+        // We thought about not generating the keypress event, but we
+        // need that repeat for backspace.  Rethink later.
+        handle_keypress(event.xkey);
+        continue;
+
+      } else {
+        // This keyrelease event is not immediately followed by a
+        // matching keypress event, so it's a genuine release.
+        handle_keyrelease(keyrelease_event);
+      }
+    }
+
+    WindowProperties properties;
+    ButtonHandle button;
+
+    switch (event.type) {
+    case ReparentNotify:
+      break;
+
+    case ConfigureNotify:
+      _awaiting_configure = false;
+      if (_properties.get_fixed_size()) {
+        // If the window properties indicate a fixed size only, undo
+        // any attempt by the user to change them.  In X, there
+        // doesn't appear to be a way to universally disallow this
+        // directly (although we do set the min_size and max_size to
+        // the same value, which seems to work for most window
+        // managers.)
+        WindowProperties current_props = get_properties();
+        if (event.xconfigure.width != current_props.get_x_size() ||
+            event.xconfigure.height != current_props.get_y_size()) {
+          XWindowChanges changes;
+          changes.width = current_props.get_x_size();
+          changes.height = current_props.get_y_size();
+          int value_mask = (CWWidth | CWHeight);
+          XConfigureWindow(_display, _xwindow, value_mask, &changes);
+        }
+
+      } else {
+        // A normal window may be resized by the user at will.
+        properties.set_size(event.xconfigure.width, event.xconfigure.height);
+        system_changed_properties(properties);
+      }
+      break;
+
+    case ButtonPress:
+      // This refers to the mouse buttons.
+      button = get_mouse_button(event.xbutton);
+      _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
+      _input_devices[0].button_down(button);
+      break;
+
+    case ButtonRelease:
+      button = get_mouse_button(event.xbutton);
+      _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y);
+      _input_devices[0].button_up(button);
+      break;
+
+    case MotionNotify:
+      _input_devices[0].set_pointer_in_window(event.xmotion.x, event.xmotion.y);
+      break;
+
+    case KeyPress:
+      handle_keystroke(event.xkey);
+      handle_keypress(event.xkey);
+      break;
+
+    case KeyRelease:
+      // The KeyRelease can't be processed immediately, because we
+      // have to check first if it's immediately followed by a
+      // matching KeyPress event.
+      keyrelease_event = event.xkey;
+      got_keyrelease_event = true;
+      break;
+
+    case EnterNotify:
+      _input_devices[0].set_pointer_in_window(event.xcrossing.x, event.xcrossing.y);
+      break;
+
+    case LeaveNotify:
+      _input_devices[0].set_pointer_out_of_window();
+      break;
+
+    case FocusIn:
+      properties.set_foreground(true);
+      system_changed_properties(properties);
+      break;
+
+    case FocusOut:
+      properties.set_foreground(false);
+      system_changed_properties(properties);
+      break;
+
+    case UnmapNotify:
+      properties.set_minimized(true);
+      system_changed_properties(properties);
+      break;
+
+    case MapNotify:
+      properties.set_minimized(false);
+      system_changed_properties(properties);
+
+      // Auto-focus the window when it is mapped.
+      XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
+      break;
+
+    case ClientMessage:
+      if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window) {
+        // This is a message from the window manager indicating that
+        // the user has requested to close the window.
+        string close_request_event = get_close_request_event();
+        if (!close_request_event.empty()) {
+          // In this case, the app has indicated a desire to intercept
+          // the request and process it directly.
+          throw_event(close_request_event);
+
+        } else {
+          // In this case, the default case, the app does not intend
+          // to service the request, so we do by closing the window.
+
+          // TODO: don't release the gsg in the window thread.
+          close_window();
+          properties.set_open(false);
+          system_changed_properties(properties);
+        }
+      }
+      break;
+
+    case DestroyNotify:
+      // Apparently, we never get a DestroyNotify on a toplevel
+      // window.  Instead, we rely on hints from the window manager
+      // (see above).
+      egldisplay_cat.info()
+        << "DestroyNotify\n";
+      break;
+
+    default:
+      egldisplay_cat.error()
+        << "unhandled X event type " << event.type << "\n";
+    }
+  }
+
+  if (got_keyrelease_event) {
+    // This keyrelease event is not immediately followed by a
+    // matching keypress event, so it's a genuine release.
+    handle_keyrelease(keyrelease_event);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::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 eglGraphicsWindow::
+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;
+  }
+
+  eglGraphicsPipe *egl_pipe;
+  DCAST_INTO_V(egl_pipe, _pipe);
+
+  // Fullscreen mode is implemented with a hint to the window manager.
+  // However, we also implicitly set the origin to (0, 0) and the size
+  // to the desktop size, and request undecorated mode, in case the
+  // user has a less-capable window manager (or no window manager at
+  // all).
+  if (properties.get_fullscreen()) {
+    properties.set_undecorated(true);
+    properties.set_origin(0, 0);
+    properties.set_size(egl_pipe->get_display_width(),
+                        egl_pipe->get_display_height());
+  }
+
+  GraphicsWindow::set_properties_now(properties);
+  if (!properties.is_any_specified()) {
+    // The base class has already handled this case.
+    return;
+  }
+
+  // The window is already open; we are limited to what we can change
+  // on the fly.
+
+  // We'll pass some property requests on as a window manager hint.
+  WindowProperties wm_properties = _properties;
+  wm_properties.add_properties(properties);
+
+  // The window title may be changed by issuing another hint request.
+  // Assume this will be honored.
+  if (properties.has_title()) {
+    _properties.set_title(properties.get_title());
+    properties.clear_title();
+  }
+
+  // Ditto for fullscreen mode.
+  if (properties.has_fullscreen()) {
+    _properties.set_fullscreen(properties.get_fullscreen());
+    properties.clear_fullscreen();
+  }
+
+  // The size and position of an already-open window are changed via
+  // explicit X calls.  These may still get intercepted by the window
+  // manager.  Rather than changing _properties immediately, we'll
+  // wait for the ConfigureNotify message to come back.
+  XWindowChanges changes;
+  int value_mask = 0;
+
+  if (properties.has_origin()) {
+    changes.x = properties.get_x_origin();
+    changes.y = properties.get_y_origin();
+    value_mask |= (CWX | CWY);
+    properties.clear_origin();
+  }
+  if (properties.has_size()) {
+    changes.width = properties.get_x_size();
+    changes.height = properties.get_y_size();
+    value_mask |= (CWWidth | CWHeight);
+    properties.clear_size();
+  }
+  if (properties.has_z_order()) {
+    // We'll send the classic stacking request through the standard
+    // interface, for users of primitive window managers; but we'll
+    // also send it as a window manager hint, for users of modern
+    // window managers.
+    _properties.set_z_order(properties.get_z_order());
+    switch (properties.get_z_order()) {
+    case WindowProperties::Z_bottom:
+      changes.stack_mode = Below;
+      break;
+
+    case WindowProperties::Z_normal:
+      changes.stack_mode = TopIf;
+      break;
+
+    case WindowProperties::Z_top:
+      changes.stack_mode = Above;
+      break;
+    }
+
+    value_mask |= (CWStackMode);
+    properties.clear_z_order();
+  }
+
+  if (value_mask != 0) {
+    XReconfigureWMWindow(_display, _xwindow, _screen, value_mask, &changes);
+
+    // Don't draw anything until this is done reconfiguring.
+    _awaiting_configure = true;
+  }
+
+  // We hide the cursor by setting it to an invisible pixmap.
+  if (properties.has_cursor_hidden()) {
+    _properties.set_cursor_hidden(properties.get_cursor_hidden());
+    if (properties.get_cursor_hidden()) {
+      XDefineCursor(_display, _xwindow, egl_pipe->get_hidden_cursor());
+    } else {
+      XDefineCursor(_display, _xwindow, None);
+    }
+    properties.clear_cursor_hidden();
+  }
+
+  if (properties.has_foreground()) {
+    if (properties.get_foreground()) {
+      XSetInputFocus(_display, _xwindow, RevertToPointerRoot, CurrentTime);
+    } else {
+      XSetInputFocus(_display, PointerRoot, RevertToPointerRoot, CurrentTime);
+    }
+    properties.clear_foreground();
+  }
+
+  set_wm_properties(wm_properties, true);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::close_window
+//       Access: Protected, Virtual
+//  Description: Closes the window right now.  Called from the window
+//               thread.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsWindow::
+close_window() {
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+    if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+      egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
+        << get_egl_error_string(eglGetError()) << "\n";
+    }
+    _gsg.clear();
+    _active = false;
+  }
+
+  if (_ic != (XIC)NULL) {
+    XDestroyIC(_ic);
+    _ic = (XIC)NULL;
+  }
+
+  if (_egl_surface != 0) {
+    if (!eglDestroySurface(_egl_display, _egl_surface)) {
+      egldisplay_cat.error() << "Failed to destroy surface: "
+        << get_egl_error_string(eglGetError()) << "\n";
+    }
+  }
+
+  if (_xwindow != (Window)NULL) {
+    XDestroyWindow(_display, _xwindow);
+    _xwindow = (Window)NULL;
+
+    // This may be necessary if we just closed the last X window in an
+    // application, so the server hears the close request.
+    XFlush(_display);
+  }
+  GraphicsWindow::close_window();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::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 eglGraphicsWindow::
+open_window() {
+  eglGraphicsPipe *egl_pipe;
+  DCAST_INTO_R(egl_pipe, _pipe, false);
+
+  // GSG Creation/Initialization
+  eglGraphicsStateGuardian *eglgsg;
+  if (_gsg == 0) {
+    // There is no old gsg.  Create a new one.
+    eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL);
+    eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), false, false);
+    _gsg = eglgsg;
+  } else {
+    // If the old gsg has the wrong pixel format, create a
+    // new one that shares with the old gsg.
+    DCAST_INTO_R(eglgsg, _gsg, false);
+    if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
+      eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
+      eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), false, false);
+      _gsg = eglgsg;
+    }
+  }
+
+  XVisualInfo *visual_info = eglgsg->_visual;
+  if (visual_info == NULL) {
+    // No X visual for this fbconfig; how can we open the window?
+    egldisplay_cat.error()
+      << "No X visual: cannot open window.\n";
+    return false;
+  }
+  Visual *visual = visual_info->visual;
+  int depth = visual_info->depth;
+
+  if (!_properties.has_origin()) {
+    _properties.set_origin(0, 0);
+  }
+  if (!_properties.has_size()) {
+    _properties.set_size(100, 100);
+  }
+
+  Window root_window;
+  if (!_properties.has_parent_window()) {
+    root_window = egl_pipe->get_root();
+  } else {
+    root_window = (Window) (int) _properties.get_parent_window();
+  }
+
+  setup_colormap(visual_info);
+
+  _event_mask =
+    ButtonPressMask | ButtonReleaseMask |
+    KeyPressMask | KeyReleaseMask |
+    EnterWindowMask | LeaveWindowMask |
+    PointerMotionMask |
+    FocusChangeMask |
+    StructureNotifyMask;
+
+  // Initialize window attributes
+  XSetWindowAttributes wa;
+  wa.background_pixel = XBlackPixel(_display, _screen);
+  wa.border_pixel = 0;
+  wa.colormap = _colormap;
+  wa.event_mask = _event_mask;
+
+  unsigned long attrib_mask =
+    CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+  _xwindow = XCreateWindow
+    (_display, root_window,
+     _properties.get_x_origin(), _properties.get_y_origin(),
+     _properties.get_x_size(), _properties.get_y_size(),
+     0, depth, InputOutput, visual, attrib_mask, &wa);
+
+  if (_xwindow == (Window)0) {
+    egldisplay_cat.error()
+      << "failed to create X window.\n";
+    return false;
+  }
+  set_wm_properties(_properties, false);
+
+  // We don't specify any fancy properties of the XIC.  It would be
+  // nicer if we could support fancy IM's that want preedit callbacks,
+  // etc., but that can wait until we have an X server that actually
+  // supports these to test it on.
+  XIM im = egl_pipe->get_im();
+  _ic = NULL;
+  if (im) {
+    _ic = XCreateIC
+      (im,
+       XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
+       (void*)NULL);
+    if (_ic == (XIC)NULL) {
+      egldisplay_cat.warning()
+        << "Couldn't create input context.\n";
+    }
+  }
+
+  if (_properties.get_cursor_hidden()) {
+    XDefineCursor(_display, _xwindow, egl_pipe->get_hidden_cursor());
+  }
+
+  _egl_surface = eglCreateWindowSurface(_egl_display, eglgsg->_fbconfig, (NativeWindowType) _xwindow, NULL);
+  if (eglGetError() != EGL_SUCCESS) {
+    egldisplay_cat.error()
+      << "Failed to create window surface.\n";
+    return false;
+  }
+
+  if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context)) {
+    egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
+      << get_egl_error_string(eglGetError()) << "\n";
+  }
+  eglgsg->reset_if_new();
+  if (!eglgsg->is_valid()) {
+    close_window();
+    return false;
+  }
+  if (!eglgsg->get_fb_properties().verify_hardware_software
+      (_fb_properties, eglgsg->get_gl_renderer())) {
+    close_window();
+    return false;
+  }
+  _fb_properties = eglgsg->get_fb_properties();
+
+  XMapWindow(_display, _xwindow);
+
+  if (_properties.get_raw_mice()) {
+    open_raw_mice();
+  } else {
+    if (egldisplay_cat.is_debug()) {
+      egldisplay_cat.debug()
+        << "Raw mice not requested.\n";
+    }
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::set_wm_properties
+//       Access: Private
+//  Description: Asks the window manager to set the appropriate
+//               properties.  In X, these properties cannot be
+//               specified directly by the application; they must be
+//               requested via the window manager, which may or may
+//               not choose to honor the request.
+//
+//               If already_mapped is true, the window has already
+//               been mapped (manifested) on the display.  This means
+//               we may need to use a different action in some cases.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsWindow::
+set_wm_properties(const WindowProperties &properties, bool already_mapped) {
+  // Name the window if there is a name
+  XTextProperty window_name;
+  XTextProperty *window_name_p = (XTextProperty *)NULL;
+  if (properties.has_title()) {
+    char *name = (char *)properties.get_title().c_str();
+    if (XStringListToTextProperty(&name, 1, &window_name) != 0) {
+      window_name_p = &window_name;
+    }
+  }
+
+  // The size hints request a window of a particular size and/or a
+  // particular placement onscreen.
+  XSizeHints *size_hints_p = NULL;
+  if (properties.has_origin() || properties.has_size()) {
+    size_hints_p = XAllocSizeHints();
+    if (size_hints_p != (XSizeHints *)NULL) {
+      if (properties.has_origin()) {
+        size_hints_p->x = properties.get_x_origin();
+        size_hints_p->y = properties.get_y_origin();
+        size_hints_p->flags |= USPosition;
+      }
+      if (properties.has_size()) {
+        size_hints_p->width = properties.get_x_size();
+        size_hints_p->height = properties.get_y_size();
+        size_hints_p->flags |= USSize;
+
+        if (properties.has_fixed_size()) {
+          size_hints_p->min_width = properties.get_x_size();
+          size_hints_p->min_height = properties.get_y_size();
+          size_hints_p->max_width = properties.get_x_size();
+          size_hints_p->max_height = properties.get_y_size();
+          size_hints_p->flags |= (PMinSize | PMaxSize);
+        }
+      }
+    }
+  }
+
+  // The window manager hints include requests to the window manager
+  // other than those specific to window geometry.
+  XWMHints *wm_hints_p = NULL;
+  wm_hints_p = XAllocWMHints();
+  if (wm_hints_p != (XWMHints *)NULL) {
+    if (properties.has_minimized() && properties.get_minimized()) {
+      wm_hints_p->initial_state = IconicState;
+    } else {
+      wm_hints_p->initial_state = NormalState;
+    }
+    wm_hints_p->flags = StateHint;
+  }
+
+  // Two competing window manager interfaces have evolved.  One of
+  // them allows to set certain properties as a "type"; the other one
+  // as a "state".  We'll try to honor both.
+  static const int max_type_data = 32;
+  PN_int32 type_data[max_type_data];
+  int next_type_data = 0;
+
+  static const int max_state_data = 32;
+  PN_int32 state_data[max_state_data];
+  int next_state_data = 0;
+
+  static const int max_set_data = 32;
+  class SetAction {
+  public:
+    inline SetAction() { }
+    inline SetAction(Atom state, Atom action) : _state(state), _action(action) { }
+    Atom _state;
+    Atom _action;
+  };
+  SetAction set_data[max_set_data];
+  int next_set_data = 0;
+
+  if (properties.get_fullscreen()) {
+    // For a "fullscreen" request, we pass this through, hoping the
+    // window manager will support EWMH.
+    type_data[next_type_data++] = _net_wm_window_type_fullscreen;
+
+    // We also request it as a state.
+    state_data[next_state_data++] = _net_wm_state_fullscreen;
+    set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, _net_wm_state_add);
+  } else {
+    set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, _net_wm_state_remove);
+  }
+
+  // If we asked for a window without a border, there's no excellent
+  // way to arrange that.  For users whose window managers follow the
+  // EWMH specification, we can ask for a "splash" screen, which is
+  // usually undecorated.  It's not exactly right, but the spec
+  // doesn't give us an exactly-right option.
+
+  // For other users, we'll totally punt and just set the window's
+  // Class to "Undecorated", and let the user configure his/her window
+  // manager not to put a border around windows of this class.
+  XClassHint *class_hints_p = NULL;
+  if (properties.get_undecorated()) {
+    class_hints_p = XAllocClassHint();
+    class_hints_p->res_class = (char*) "Undecorated";
+
+    if (!properties.get_fullscreen()) {
+      type_data[next_type_data++] = _net_wm_window_type_splash;
+    }
+  }
+
+  if (properties.has_z_order()) {
+    switch (properties.get_z_order()) {
+    case WindowProperties::Z_bottom:
+      state_data[next_state_data++] = _net_wm_state_below;
+      set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_add);
+      set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove);
+      break;
+
+    case WindowProperties::Z_normal:
+      set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove);
+      set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove);
+      break;
+
+    case WindowProperties::Z_top:
+      state_data[next_state_data++] = _net_wm_state_above;
+      set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove);
+      set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_add);
+      break;
+    }
+  }
+
+  nassertv(next_type_data < max_type_data);
+  nassertv(next_state_data < max_state_data);
+  nassertv(next_set_data < max_set_data);
+
+  XChangeProperty(_display, _xwindow, _net_wm_window_type,
+                  XA_ATOM, 32, PropModeReplace,
+                  (unsigned char *)type_data, next_type_data);
+
+  // Request the state properties all at once.
+  XChangeProperty(_display, _xwindow, _net_wm_state,
+                  XA_ATOM, 32, PropModeReplace,
+                  (unsigned char *)state_data, next_state_data);
+
+  if (already_mapped) {
+    // We have to request state changes differently when the window
+    // has been mapped.  To do this, we need to send a client message
+    // to the root window for each change.
+
+    eglGraphicsPipe *egl_pipe;
+    DCAST_INTO_V(egl_pipe, _pipe);
+
+    for (int i = 0; i < next_set_data; ++i) {
+      XClientMessageEvent event;
+      memset(&event, 0, sizeof(event));
+
+      event.type = ClientMessage;
+      event.send_event = True;
+      event.display = _display;
+      event.window = _xwindow;
+      event.message_type = _net_wm_state;
+      event.format = 32;
+      event.data.l[0] = set_data[i]._action;
+      event.data.l[1] = set_data[i]._state;
+      event.data.l[2] = 0;
+      event.data.l[3] = 1;
+
+      XSendEvent(_display, egl_pipe->get_root(), True, 0, (XEvent *)&event);
+    }
+  }
+
+  XSetWMProperties(_display, _xwindow, window_name_p, window_name_p,
+                   NULL, 0, size_hints_p, wm_hints_p, class_hints_p);
+
+  if (size_hints_p != (XSizeHints *)NULL) {
+    XFree(size_hints_p);
+  }
+  if (wm_hints_p != (XWMHints *)NULL) {
+    XFree(wm_hints_p);
+  }
+  if (class_hints_p != (XClassHint *)NULL) {
+    XFree(class_hints_p);
+  }
+
+  // Also, indicate to the window manager that we'd like to get a
+  // chance to close our windows cleanly, rather than being rudely
+  // disconnected from the X server if the user requests a window
+  // close.
+  Atom protocols[] = {
+    _wm_delete_window,
+  };
+
+  XSetWMProtocols(_display, _xwindow, protocols,
+                  sizeof(protocols) / sizeof(Atom));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::setup_colormap
+//       Access: Private
+//  Description: Allocates a colormap appropriate to the visual and
+//               stores in in the _colormap method.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsWindow::
+setup_colormap(XVisualInfo *visual) {
+  eglGraphicsPipe *egl_pipe;
+  DCAST_INTO_V(egl_pipe, _pipe);
+  Window root_window = egl_pipe->get_root();
+
+  int visual_class = visual->c_class;
+  int rc, is_rgb;
+
+  switch (visual_class) {
+    case PseudoColor:
+      _colormap = XCreateColormap(_display, root_window,
+                                  visual->visual, AllocAll);
+      break;
+    case TrueColor:
+    case DirectColor:
+      _colormap = XCreateColormap(_display, root_window,
+                                  visual->visual, AllocNone);
+      break;
+    case StaticColor:
+    case StaticGray:
+    case GrayScale:
+      _colormap = XCreateColormap(_display, root_window,
+                                  visual->visual, AllocNone);
+      break;
+    default:
+      egldisplay_cat.error()
+        << "Could not allocate a colormap for visual class "
+        << visual_class << ".\n";
+      break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::open_raw_mice
+//       Access: Private
+//  Description: Adds raw mice to the _input_devices list.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsWindow::
+open_raw_mice()
+{
+#ifdef HAVE_LINUX_INPUT_H
+  bool any_present = false;
+  bool any_mice = false;
+
+  for (int i=0; i<64; i++) {
+    uint8_t evtypes[EV_MAX/8 + 1];
+    ostringstream fnb;
+    fnb << "/dev/input/event" << i;
+    string fn = fnb.str();
+    int fd = open(fn.c_str(), O_RDONLY | O_NONBLOCK, 0);
+    if (fd >= 0) {
+      any_present = true;
+      char name[256];
+      char phys[256];
+      char uniq[256];
+      if ((ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0)||
+          (ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) < 0)||
+          (ioctl(fd, EVIOCGPHYS(sizeof(uniq)), uniq) < 0)||
+          (ioctl(fd, EVIOCGBIT(0, EV_MAX), &evtypes) < 0)) {
+        close(fd);
+        egldisplay_cat.error() <<
+          "Opening raw mice: ioctl failed on " << fn << "\n";
+      } else {
+        if (test_bit(EV_REL, evtypes) || test_bit(EV_ABS, evtypes)) {
+          for (char *p=name; *p; p++) {
+            if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) {
+              *p = '_';
+            }
+          }
+          for (char *p=uniq; *p; p++) {
+            if (((*p<'a')||(*p>'z')) && ((*p<'A')||(*p>'Z')) && ((*p<'0')||(*p>'9'))) {
+              *p = '_';
+            }
+          }
+          string full_id = ((string)name) + "." + uniq;
+          MouseDeviceInfo inf;
+          inf._fd = fd;
+          inf._input_device_index = _input_devices.size();
+          inf._io_buffer = "";
+          _mouse_device_info.push_back(inf);
+          GraphicsWindowInputDevice device =
+            GraphicsWindowInputDevice::pointer_only(this, full_id);
+          add_input_device(device);
+          egldisplay_cat.info() << "Raw mouse " <<
+            inf._input_device_index << " detected: " << full_id << "\n";
+          any_mice = true;
+        } else {
+          close(fd);
+        }
+      }
+    } else {
+      if ((errno == ENOENT)||(errno == ENOTDIR)) {
+        break;
+      } else {
+        any_present = true;
+        egldisplay_cat.error() <<
+          "Opening raw mice: " << strerror(errno) << " " << fn << "\n";
+      }
+    }
+  }
+
+  if (!any_present) {
+    egldisplay_cat.error() <<
+      "Opening raw mice: files not found: /dev/input/event*\n";
+  } else if (!any_mice) {
+    egldisplay_cat.error() <<
+      "Opening raw mice: no mouse devices detected in /dev/input/event*\n";
+  }
+#else
+  egldisplay_cat.error() <<
+    "Opening raw mice: panda not compiled with raw mouse support.\n";
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::poll_raw_mice
+//       Access: Private
+//  Description: Reads events from the raw mouse device files.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsWindow::
+poll_raw_mice()
+{
+#ifdef HAVE_LINUX_INPUT_H
+  for (int dev=0; dev<_mouse_device_info.size(); dev++) {
+    MouseDeviceInfo &inf = _mouse_device_info[dev];
+
+    // Read all bytes into buffer.
+    if (inf._fd >= 0) {
+      while (1) {
+        char tbuf[1024];
+        int nread = read(inf._fd, tbuf, sizeof(tbuf));
+        if (nread > 0) {
+          inf._io_buffer += string(tbuf, nread);
+        } else {
+          if ((nread < 0)&&((errno == EWOULDBLOCK) || (errno==EAGAIN))) {
+            break;
+          }
+          close(inf._fd);
+          inf._fd = -1;
+          break;
+        }
+      }
+    }
+
+    // Process events.
+    int nevents = inf._io_buffer.size() / sizeof(struct input_event);
+    if (nevents == 0) {
+      continue;
+    }
+    const input_event *events = (const input_event *)(inf._io_buffer.c_str());
+    GraphicsWindowInputDevice &dev = _input_devices[inf._input_device_index];
+    int x = dev.get_raw_pointer().get_x();
+    int y = dev.get_raw_pointer().get_y();
+    for (int i=0; i<nevents; i++) {
+      if (events[i].type == EV_REL) {
+        if (events[i].code == REL_X) x += events[i].value;
+        if (events[i].code == REL_Y) y += events[i].value;
+      } else if (events[i].type == EV_ABS) {
+        if (events[i].code == ABS_X) x = events[i].value;
+        if (events[i].code == ABS_Y) y = events[i].value;
+      } else if (events[i].type == EV_KEY) {
+        if ((events[i].code >= BTN_MOUSE)&&(events[i].code < BTN_MOUSE+8)) {
+          int btn = events[i].code - BTN_MOUSE;
+          dev.set_pointer_in_window(x,y);
+          if (events[i].value) {
+            dev.button_down(MouseButton::button(btn));
+          } else {
+            dev.button_up(MouseButton::button(btn));
+          }
+        }
+      }
+    }
+    inf._io_buffer.erase(0,nevents*sizeof(struct input_event));
+    dev.set_pointer_in_window(x,y);
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::handle_keystroke
+//       Access: Private
+//  Description: Generates a keystroke corresponding to the indicated
+//               X KeyPress event.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsWindow::
+handle_keystroke(XKeyEvent &event) {
+  _input_devices[0].set_pointer_in_window(event.x, event.y);
+
+  if (_ic) {
+    // First, get the keystroke as a wide-character sequence.
+    static const int buffer_size = 256;
+    wchar_t buffer[buffer_size];
+    Status status;
+    int len = XwcLookupString(_ic, &event, buffer, buffer_size, NULL,
+                              &status);
+    if (status == XBufferOverflow) {
+      egldisplay_cat.error()
+        << "Overflowed input buffer.\n";
+    }
+
+    // Now each of the returned wide characters represents a
+    // keystroke.
+    for (int i = 0; i < len; i++) {
+      _input_devices[0].keystroke(buffer[i]);
+    }
+
+  } else {
+    // Without an input context, just get the ascii keypress.
+    ButtonHandle button = get_button(event, true);
+    if (button.has_ascii_equivalent()) {
+      _input_devices[0].keystroke(button.get_ascii_equivalent());
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::handle_keypress
+//       Access: Private
+//  Description: Generates a keypress corresponding to the indicated
+//               X KeyPress event.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsWindow::
+handle_keypress(XKeyEvent &event) {
+  _input_devices[0].set_pointer_in_window(event.x, event.y);
+
+  // Now get the raw unshifted button.
+  ButtonHandle button = get_button(event, false);
+  if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
+    _input_devices[0].button_down(KeyboardButton::control());
+  }
+  if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
+    _input_devices[0].button_down(KeyboardButton::shift());
+  }
+  if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
+    _input_devices[0].button_down(KeyboardButton::alt());
+  }
+  if (button != ButtonHandle::none()) {
+    _input_devices[0].button_down(button);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::handle_keyrelease
+//       Access: Private
+//  Description: Generates a keyrelease corresponding to the indicated
+//               X KeyRelease event.
+////////////////////////////////////////////////////////////////////
+void eglGraphicsWindow::
+handle_keyrelease(XKeyEvent &event) {
+  _input_devices[0].set_pointer_in_window(event.x, event.y);
+
+  // Now get the raw unshifted button.
+  ButtonHandle button = get_button(event, false);
+  if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
+    _input_devices[0].button_up(KeyboardButton::control());
+  }
+  if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
+    _input_devices[0].button_up(KeyboardButton::shift());
+  }
+  if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
+    _input_devices[0].button_up(KeyboardButton::alt());
+  }
+  if (button != ButtonHandle::none()) {
+    _input_devices[0].button_up(button);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::get_button
+//       Access: Private
+//  Description: Returns the Panda ButtonHandle corresponding to the
+//               keyboard button indicated by the given key event.
+////////////////////////////////////////////////////////////////////
+ButtonHandle eglGraphicsWindow::
+get_button(XKeyEvent &key_event, bool allow_shift) {
+  KeySym key = XLookupKeysym(&key_event, 0);
+
+  if ((key_event.state & Mod2Mask) != 0) {
+    // Mod2Mask corresponds to NumLock being in effect.  In this case,
+    // we want to get the alternate keysym associated with any keypad
+    // keys.  Weird system.
+    KeySym k2;
+    ButtonHandle button;
+    switch (key) {
+    case XK_KP_Space:
+    case XK_KP_Tab:
+    case XK_KP_Enter:
+    case XK_KP_F1:
+    case XK_KP_F2:
+    case XK_KP_F3:
+    case XK_KP_F4:
+    case XK_KP_Equal:
+    case XK_KP_Multiply:
+    case XK_KP_Add:
+    case XK_KP_Separator:
+    case XK_KP_Subtract:
+    case XK_KP_Divide:
+    case XK_KP_Left:
+    case XK_KP_Up:
+    case XK_KP_Right:
+    case XK_KP_Down:
+    case XK_KP_Begin:
+    case XK_KP_Prior:
+    case XK_KP_Next:
+    case XK_KP_Home:
+    case XK_KP_End:
+    case XK_KP_Insert:
+    case XK_KP_Delete:
+    case XK_KP_0:
+    case XK_KP_1:
+    case XK_KP_2:
+    case XK_KP_3:
+    case XK_KP_4:
+    case XK_KP_5:
+    case XK_KP_6:
+    case XK_KP_7:
+    case XK_KP_8:
+    case XK_KP_9:
+      k2 = XLookupKeysym(&key_event, 1);
+      button = map_button(k2);
+      if (button != ButtonHandle::none()) {
+        return button;
+      }
+      // If that didn't produce a button we know, just fall through
+      // and handle the normal, un-numlocked key.
+      break;
+
+    default:
+      break;
+    }
+  }
+
+  if (allow_shift) {
+    // If shift is held down, get the shifted keysym.
+    if ((key_event.state & ShiftMask) != 0) {
+      KeySym k2 = XLookupKeysym(&key_event, 1);
+      ButtonHandle button = map_button(k2);
+      if (button != ButtonHandle::none()) {
+        return button;
+      }
+    }
+
+    // If caps lock is down, shift lowercase letters to uppercase.  We
+    // can do this in just the ASCII set, because we handle
+    // international keyboards elsewhere (via an input context).
+    if ((key_event.state & (ShiftMask | LockMask)) != 0) {
+      if (key >= XK_a and key <= XK_z) {
+        key += (XK_A - XK_a);
+      }
+    }
+  }
+
+  return map_button(key);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::map_button
+//       Access: Private
+//  Description: Maps from a single X keysym to Panda's ButtonHandle.
+//               Called by get_button(), above.
+////////////////////////////////////////////////////////////////////
+ButtonHandle eglGraphicsWindow::
+map_button(KeySym key) {
+  switch (key) {
+  case XK_BackSpace:
+    return KeyboardButton::backspace();
+  case XK_Tab:
+  case XK_KP_Tab:
+    return KeyboardButton::tab();
+  case XK_Return:
+  case XK_KP_Enter:
+    return KeyboardButton::enter();
+  case XK_Escape:
+    return KeyboardButton::escape();
+  case XK_KP_Space:
+  case XK_space:
+    return KeyboardButton::space();
+  case XK_exclam:
+    return KeyboardButton::ascii_key('!');
+  case XK_quotedbl:
+    return KeyboardButton::ascii_key('"');
+  case XK_numbersign:
+    return KeyboardButton::ascii_key('#');
+  case XK_dollar:
+    return KeyboardButton::ascii_key('$');
+  case XK_percent:
+    return KeyboardButton::ascii_key('%');
+  case XK_ampersand:
+    return KeyboardButton::ascii_key('&');
+  case XK_apostrophe: // == XK_quoteright
+    return KeyboardButton::ascii_key('\'');
+  case XK_parenleft:
+    return KeyboardButton::ascii_key('(');
+  case XK_parenright:
+    return KeyboardButton::ascii_key(')');
+  case XK_asterisk:
+  case XK_KP_Multiply:
+    return KeyboardButton::ascii_key('*');
+  case XK_plus:
+  case XK_KP_Add:
+    return KeyboardButton::ascii_key('+');
+  case XK_comma:
+  case XK_KP_Separator:
+    return KeyboardButton::ascii_key(',');
+  case XK_minus:
+  case XK_KP_Subtract:
+    return KeyboardButton::ascii_key('-');
+  case XK_period:
+  case XK_KP_Decimal:
+    return KeyboardButton::ascii_key('.');
+  case XK_slash:
+  case XK_KP_Divide:
+    return KeyboardButton::ascii_key('/');
+  case XK_0:
+  case XK_KP_0:
+    return KeyboardButton::ascii_key('0');
+  case XK_1:
+  case XK_KP_1:
+    return KeyboardButton::ascii_key('1');
+  case XK_2:
+  case XK_KP_2:
+    return KeyboardButton::ascii_key('2');
+  case XK_3:
+  case XK_KP_3:
+    return KeyboardButton::ascii_key('3');
+  case XK_4:
+  case XK_KP_4:
+    return KeyboardButton::ascii_key('4');
+  case XK_5:
+  case XK_KP_5:
+    return KeyboardButton::ascii_key('5');
+  case XK_6:
+  case XK_KP_6:
+    return KeyboardButton::ascii_key('6');
+  case XK_7:
+  case XK_KP_7:
+    return KeyboardButton::ascii_key('7');
+  case XK_8:
+  case XK_KP_8:
+    return KeyboardButton::ascii_key('8');
+  case XK_9:
+  case XK_KP_9:
+    return KeyboardButton::ascii_key('9');
+  case XK_colon:
+    return KeyboardButton::ascii_key(':');
+  case XK_semicolon:
+    return KeyboardButton::ascii_key(';');
+  case XK_less:
+    return KeyboardButton::ascii_key('<');
+  case XK_equal:
+  case XK_KP_Equal:
+    return KeyboardButton::ascii_key('=');
+  case XK_greater:
+    return KeyboardButton::ascii_key('>');
+  case XK_question:
+    return KeyboardButton::ascii_key('?');
+  case XK_at:
+    return KeyboardButton::ascii_key('@');
+  case XK_A:
+    return KeyboardButton::ascii_key('A');
+  case XK_B:
+    return KeyboardButton::ascii_key('B');
+  case XK_C:
+    return KeyboardButton::ascii_key('C');
+  case XK_D:
+    return KeyboardButton::ascii_key('D');
+  case XK_E:
+    return KeyboardButton::ascii_key('E');
+  case XK_F:
+    return KeyboardButton::ascii_key('F');
+  case XK_G:
+    return KeyboardButton::ascii_key('G');
+  case XK_H:
+    return KeyboardButton::ascii_key('H');
+  case XK_I:
+    return KeyboardButton::ascii_key('I');
+  case XK_J:
+    return KeyboardButton::ascii_key('J');
+  case XK_K:
+    return KeyboardButton::ascii_key('K');
+  case XK_L:
+    return KeyboardButton::ascii_key('L');
+  case XK_M:
+    return KeyboardButton::ascii_key('M');
+  case XK_N:
+    return KeyboardButton::ascii_key('N');
+  case XK_O:
+    return KeyboardButton::ascii_key('O');
+  case XK_P:
+    return KeyboardButton::ascii_key('P');
+  case XK_Q:
+    return KeyboardButton::ascii_key('Q');
+  case XK_R:
+    return KeyboardButton::ascii_key('R');
+  case XK_S:
+    return KeyboardButton::ascii_key('S');
+  case XK_T:
+    return KeyboardButton::ascii_key('T');
+  case XK_U:
+    return KeyboardButton::ascii_key('U');
+  case XK_V:
+    return KeyboardButton::ascii_key('V');
+  case XK_W:
+    return KeyboardButton::ascii_key('W');
+  case XK_X:
+    return KeyboardButton::ascii_key('X');
+  case XK_Y:
+    return KeyboardButton::ascii_key('Y');
+  case XK_Z:
+    return KeyboardButton::ascii_key('Z');
+  case XK_bracketleft:
+    return KeyboardButton::ascii_key('[');
+  case XK_backslash:
+    return KeyboardButton::ascii_key('\\');
+  case XK_bracketright:
+    return KeyboardButton::ascii_key(']');
+  case XK_asciicircum:
+    return KeyboardButton::ascii_key('^');
+  case XK_underscore:
+    return KeyboardButton::ascii_key('_');
+  case XK_grave: // == XK_quoteleft
+    return KeyboardButton::ascii_key('`');
+  case XK_a:
+    return KeyboardButton::ascii_key('a');
+  case XK_b:
+    return KeyboardButton::ascii_key('b');
+  case XK_c:
+    return KeyboardButton::ascii_key('c');
+  case XK_d:
+    return KeyboardButton::ascii_key('d');
+  case XK_e:
+    return KeyboardButton::ascii_key('e');
+  case XK_f:
+    return KeyboardButton::ascii_key('f');
+  case XK_g:
+    return KeyboardButton::ascii_key('g');
+  case XK_h:
+    return KeyboardButton::ascii_key('h');
+  case XK_i:
+    return KeyboardButton::ascii_key('i');
+  case XK_j:
+    return KeyboardButton::ascii_key('j');
+  case XK_k:
+    return KeyboardButton::ascii_key('k');
+  case XK_l:
+    return KeyboardButton::ascii_key('l');
+  case XK_m:
+    return KeyboardButton::ascii_key('m');
+  case XK_n:
+    return KeyboardButton::ascii_key('n');
+  case XK_o:
+    return KeyboardButton::ascii_key('o');
+  case XK_p:
+    return KeyboardButton::ascii_key('p');
+  case XK_q:
+    return KeyboardButton::ascii_key('q');
+  case XK_r:
+    return KeyboardButton::ascii_key('r');
+  case XK_s:
+    return KeyboardButton::ascii_key('s');
+  case XK_t:
+    return KeyboardButton::ascii_key('t');
+  case XK_u:
+    return KeyboardButton::ascii_key('u');
+  case XK_v:
+    return KeyboardButton::ascii_key('v');
+  case XK_w:
+    return KeyboardButton::ascii_key('w');
+  case XK_x:
+    return KeyboardButton::ascii_key('x');
+  case XK_y:
+    return KeyboardButton::ascii_key('y');
+  case XK_z:
+    return KeyboardButton::ascii_key('z');
+  case XK_braceleft:
+    return KeyboardButton::ascii_key('{');
+  case XK_bar:
+    return KeyboardButton::ascii_key('|');
+  case XK_braceright:
+    return KeyboardButton::ascii_key('}');
+  case XK_asciitilde:
+    return KeyboardButton::ascii_key('~');
+  case XK_F1:
+  case XK_KP_F1:
+    return KeyboardButton::f1();
+  case XK_F2:
+  case XK_KP_F2:
+    return KeyboardButton::f2();
+  case XK_F3:
+  case XK_KP_F3:
+    return KeyboardButton::f3();
+  case XK_F4:
+  case XK_KP_F4:
+    return KeyboardButton::f4();
+  case XK_F5:
+    return KeyboardButton::f5();
+  case XK_F6:
+    return KeyboardButton::f6();
+  case XK_F7:
+    return KeyboardButton::f7();
+  case XK_F8:
+    return KeyboardButton::f8();
+  case XK_F9:
+    return KeyboardButton::f9();
+  case XK_F10:
+    return KeyboardButton::f10();
+  case XK_F11:
+    return KeyboardButton::f11();
+  case XK_F12:
+    return KeyboardButton::f12();
+  case XK_KP_Left:
+  case XK_Left:
+    return KeyboardButton::left();
+  case XK_KP_Up:
+  case XK_Up:
+    return KeyboardButton::up();
+  case XK_KP_Right:
+  case XK_Right:
+    return KeyboardButton::right();
+  case XK_KP_Down:
+  case XK_Down:
+    return KeyboardButton::down();
+  case XK_KP_Prior:
+  case XK_Prior:
+    return KeyboardButton::page_up();
+  case XK_KP_Next:
+  case XK_Next:
+    return KeyboardButton::page_down();
+  case XK_KP_Home:
+  case XK_Home:
+    return KeyboardButton::home();
+  case XK_KP_End:
+  case XK_End:
+    return KeyboardButton::end();
+  case XK_KP_Insert:
+  case XK_Insert:
+    return KeyboardButton::insert();
+  case XK_KP_Delete:
+  case XK_Delete:
+    return KeyboardButton::del();
+  case XK_Num_Lock:
+    return KeyboardButton::num_lock();
+  case XK_Scroll_Lock:
+    return KeyboardButton::scroll_lock();
+  case XK_Print:
+    return KeyboardButton::print_screen();
+  case XK_Pause:
+    return KeyboardButton::pause();
+  case XK_Shift_L:
+    return KeyboardButton::lshift();
+  case XK_Shift_R:
+    return KeyboardButton::rshift();
+  case XK_Control_L:
+    return KeyboardButton::lcontrol();
+  case XK_Control_R:
+    return KeyboardButton::rcontrol();
+  case XK_Alt_L:
+    return KeyboardButton::lalt();
+  case XK_Alt_R:
+    return KeyboardButton::ralt();
+  case XK_Meta_L:
+  case XK_Meta_R:
+    return KeyboardButton::meta();
+  case XK_Caps_Lock:
+    return KeyboardButton::caps_lock();
+  case XK_Shift_Lock:
+    return KeyboardButton::shift_lock();
+  }
+
+  return ButtonHandle::none();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::get_mouse_button
+//       Access: Private
+//  Description: Returns the Panda ButtonHandle corresponding to the
+//               mouse button indicated by the given button event.
+////////////////////////////////////////////////////////////////////
+ButtonHandle eglGraphicsWindow::
+get_mouse_button(XButtonEvent &button_event) {
+  int index = button_event.button;
+  if (index == x_wheel_up_button) {
+    return MouseButton::wheel_up();
+  } else if (index == x_wheel_down_button) {
+    return MouseButton::wheel_down();
+  } else if (index == x_wheel_left_button) {
+    return MouseButton::wheel_left();
+  } else if (index == x_wheel_right_button) {
+    return MouseButton::wheel_right();
+  } else {
+    return MouseButton::button(index - 1);
+  }
+}
+////////////////////////////////////////////////////////////////////
+//     Function: eglGraphicsWindow::check_event
+//       Access: Private, Static
+//  Description: This function is used as a predicate to
+//               XCheckIfEvent() to determine if the indicated queued
+//               X event is relevant and should be returned to this
+//               window.
+////////////////////////////////////////////////////////////////////
+Bool eglGraphicsWindow::
+check_event(Display *display, XEvent *event, char *arg) {
+  const eglGraphicsWindow *self = (eglGraphicsWindow *)arg;
+
+  // We accept any event that is sent to our window.
+  return (event->xany.window == self->_xwindow);
+}

+ 123 - 0
panda/src/egldisplay/eglGraphicsWindow.h

@@ -0,0 +1,123 @@
+// Filename: eglGraphicsWindow.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 EGLGRAPHICSWINDOW_H
+#define EGLGRAPHICSWINDOW_H
+
+#include "pandabase.h"
+
+#include "eglGraphicsPipe.h"
+#include "graphicsWindow.h"
+#include "buttonHandle.h"
+
+#include <X11/Xutil.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : eglGraphicsWindow
+// Description : An interface to the egl system for managing GLES
+//               windows under X.
+////////////////////////////////////////////////////////////////////
+class eglGraphicsWindow : public GraphicsWindow {
+public:
+  eglGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
+                    const string &name,
+                    const FrameBufferProperties &fb_prop,
+                    const WindowProperties &win_prop,
+                    int flags,
+                    GraphicsStateGuardian *gsg,
+                    GraphicsOutput *host);
+  virtual ~eglGraphicsWindow();
+
+  virtual bool move_pointer(int device, int x, int y);
+  virtual bool begin_frame(FrameMode mode, Thread *current_thread);
+  virtual void end_frame(FrameMode mode, Thread *current_thread);
+  virtual void begin_flip();
+
+  virtual void process_events();
+  virtual void set_properties_now(WindowProperties &properties);
+
+  INLINE Window get_xwindow() const;
+
+protected:
+  virtual void close_window();
+  virtual bool open_window();
+
+private:
+  void set_wm_properties(const WindowProperties &properties,
+                         bool already_mapped);
+
+  void setup_colormap(XVisualInfo *visual);
+  void handle_keystroke(XKeyEvent &event);
+  void handle_keypress(XKeyEvent &event);
+  void handle_keyrelease(XKeyEvent &event);
+
+  ButtonHandle get_button(XKeyEvent &key_event, bool allow_shift);
+  ButtonHandle map_button(KeySym key);
+  ButtonHandle get_mouse_button(XButtonEvent &button_event);
+
+  static Bool check_event(Display *display, XEvent *event, char *arg);
+
+  void open_raw_mice();
+  void poll_raw_mice();
+
+private:
+  Display *_display;
+  int _screen;
+  Window _xwindow;
+  Colormap _colormap;
+  XIC _ic;
+  EGLDisplay _egl_display;
+  EGLSurface _egl_surface;
+
+  long _event_mask;
+  bool _awaiting_configure;
+  Atom _wm_delete_window;
+  Atom _net_wm_window_type;
+  Atom _net_wm_window_type_splash;
+  Atom _net_wm_window_type_fullscreen;
+  Atom _net_wm_state;
+  Atom _net_wm_state_fullscreen;
+  Atom _net_wm_state_above;
+  Atom _net_wm_state_below;
+  Atom _net_wm_state_add;
+  Atom _net_wm_state_remove;
+
+  struct MouseDeviceInfo {
+    int    _fd;
+    int    _input_device_index;
+    string _io_buffer;
+  };
+  pvector<MouseDeviceInfo> _mouse_device_info;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    GraphicsWindow::init_type();
+    register_type(_type_handle, "eglGraphicsWindow",
+                  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 "eglGraphicsWindow.I"
+
+#endif

+ 20 - 0
panda/src/gles2gsg/Sources.pp

@@ -0,0 +1,20 @@
+#define BUILD_DIRECTORY $[HAVE_GLES2]
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+                   dtoolutil:c dtoolbase:c dtool:m prc:c
+#define USE_PACKAGES gles2
+#begin lib_target
+  #define TARGET gles2gsg
+  #define LOCAL_LIBS \
+    glstuff gsgbase gobj display \
+    putil linmath mathutil pnmimage
+    
+  #define SOURCES \
+    config_gles2gsg.h config_gles2gsg.cxx \
+    gles2ext_shadow.h \
+    gles2gsg.h gles2gsg.cxx
+
+  #define INSTALL_HEADERS \
+    config_gles2gsg.h gles2gsg.h
+
+#end lib_target
+

+ 44 - 0
panda/src/gles2gsg/config_gles2gsg.cxx

@@ -0,0 +1,44 @@
+// Filename: config_gles2gsg.cxx
+// Created by:  pro-rsoft (14Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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_gles2gsg.h"
+#include "gles2gsg.h"
+
+#include "dconfig.h"
+
+ConfigureDef(config_gles2gsg);
+NotifyCategoryDef(gles2gsg, ":display:gsg");
+
+ConfigureFn(config_gles2gsg) {
+  init_libgles2gsg();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libgles2gsg
+//  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_libgles2gsg() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+
+  GLES2init_classes();
+}

+ 27 - 0
panda/src/gles2gsg/config_gles2gsg.h

@@ -0,0 +1,27 @@
+// Filename: config_gles2gsg.h
+// Created by:  pro-rsoft (14Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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_GLES2GSG_H
+#define CONFIG_GLES2GSG_H
+
+#include "pandabase.h"
+#include "notifyCategoryProxy.h"
+#include "dconfig.h"
+
+ConfigureDecl(config_gles2gsg, EXPCL_PANDAGLES2, EXPTP_PANDAGLES2);
+NotifyCategoryDecl(gles2gsg, EXPCL_PANDAGLES2, EXPTP_PANDAGLES2);
+
+extern EXPCL_PANDAGLES2 void init_libgles2gsg();
+
+#endif

+ 20 - 0
panda/src/gles2gsg/gles2gsg.cxx

@@ -0,0 +1,20 @@
+// Filename: gles2gsg.cxx
+// Created by:  pro-rsoft (14Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+// This is the actual .cxx file to include if you want to pick up
+// any or all of the header files in this directory as compiled to use
+// the "true" GLES2 library.
+
+#include "gles2gsg.h"
+#include "glstuff_src.cxx"

+ 74 - 0
panda/src/gles2gsg/gles2gsg.h

@@ -0,0 +1,74 @@
+// Filename: gles2gsg.h
+// Created by:  pro-rsoft (14Jun09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 GLES2GSG_H
+#define GLES2GSG_H
+
+// This header file compiles a GSG for the limited subset of OpenGL
+// that is OpenGL ES 2.
+
+#include "pandabase.h"
+#include "config_gles2gsg.h"
+
+#define GLP(name) gl##name
+#define GLUP(name) glu##name
+#define CLP(name) GLES2##name
+#define GLPREFIX_QUOTED "gl"
+#define CLASSPREFIX_QUOTED "GLES2"
+#define GLSYSTEM_NAME "OpenGL ES 2"
+#define CONFIGOBJ config_gles2gsg
+#define GLCAT gles2gsg_cat
+#define EXPCL_GL EXPCL_PANDAGLES2
+#define EXPTP_GL EXPTP_PANDAGLES2
+#ifdef OPENGLES_1
+  #error OPENGLES_1 should not be defined!
+#endif
+#ifndef OPENGLES
+  #define OPENGLES
+#endif
+#ifndef OPENGLES_2
+  #define OPENGLES_2
+#endif
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+// This helps to keep the source clean of hundreds of #ifdefs.
+#ifdef OPENGLES_2
+  #define GL_RENDERBUFFER_EXT GL_RENDERBUFFER
+  #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER
+  #define GL_DRAW_FRAMEBUFFER_EXT GL_FRAMEBUFFER
+  #define GL_READ_FRAMEBUFFER_EXT GL_FRAMEBUFFER
+  #define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE
+  #define GL_FRAMEBUFFER_UNSUPPORTED_EXT GL_FRAMEBUFFER_UNSUPPORTED
+  #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
+  #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
+  #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
+  #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT GL_FRAMEBUFFER_INCOMPLETE_FORMATS
+  #define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT
+  #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0
+  #define GL_STENCIL_ATTACHMENT_EXT GL_STENCIL_ATTACHMENT
+  #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
+  #define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES
+  #define GL_TEXTURE_3D GL_TEXTURE_3D_OES
+  #define GL_MAX_3D_TEXTURE_SIZE GL_MAX_3D_TEXTURE_SIZE_OES
+#endif
+
+#undef SUPPORT_IMMEDIATE_MODE
+#define APIENTRY
+#define APIENTRYP *
+
+#include "glstuff_src.h"
+ 
+#endif  // GLES2GSG_H

+ 1 - 0
panda/src/gles2gsg/gles2gsg_composite.cxx

@@ -0,0 +1 @@
+#include "gles2gsg_composite1.cxx"

+ 3 - 0
panda/src/gles2gsg/gles2gsg_composite1.cxx

@@ -0,0 +1,3 @@
+
+#include "config_gles2gsg.cxx"
+#include "gles2gsg.cxx"

+ 20 - 0
panda/src/glesgsg/Sources.pp

@@ -0,0 +1,20 @@
+#define BUILD_DIRECTORY $[HAVE_GLES]
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+                   dtoolutil:c dtoolbase:c dtool:m prc:c
+#define USE_PACKAGES gles
+#begin lib_target
+  #define TARGET glesgsg
+  #define LOCAL_LIBS \
+    glstuff gsgbase gobj display \
+    putil linmath mathutil pnmimage
+    
+  #define SOURCES \
+    config_glesgsg.h config_glesgsg.cxx \
+    glesext_shadow.h \
+    glesgsg.h glesgsg.cxx
+
+  #define INSTALL_HEADERS \
+    config_glesgsg.h glesgsg.h
+
+#end lib_target
+

+ 44 - 0
panda/src/glesgsg/config_glesgsg.cxx

@@ -0,0 +1,44 @@
+// Filename: config_glesgsg.cxx
+// 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."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "config_glesgsg.h"
+#include "glesgsg.h"
+
+#include "dconfig.h"
+
+ConfigureDef(config_glesgsg);
+NotifyCategoryDef(glesgsg, ":display:gsg");
+
+ConfigureFn(config_glesgsg) {
+  init_libglesgsg();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libglesgsg
+//  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_libglesgsg() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+
+  GLESinit_classes();
+}

+ 27 - 0
panda/src/glesgsg/config_glesgsg.h

@@ -0,0 +1,27 @@
+// Filename: config_glesgsg.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 CONFIG_GLESGSG_H
+#define CONFIG_GLESGSG_H
+
+#include "pandabase.h"
+#include "notifyCategoryProxy.h"
+#include "dconfig.h"
+
+ConfigureDecl(config_glesgsg, EXPCL_PANDAGLES, EXPTP_PANDAGLES);
+NotifyCategoryDecl(glesgsg, EXPCL_PANDAGLES, EXPTP_PANDAGLES);
+
+extern EXPCL_PANDAGLES void init_libglesgsg();
+
+#endif

+ 5 - 1
panda/src/iphonedisplay/glesgsg.mm → panda/src/glesgsg/glesgsg.cxx

@@ -1,5 +1,5 @@
 // Filename: glesgsg.cxx
-// Created by:  drose (09Apr09)
+// Created by:  pro-rsoft (21May09)
 //
 ////////////////////////////////////////////////////////////////////
 //
@@ -12,5 +12,9 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+// This is the actual .cxx file to include if you want to pick up
+// any or all of the header files in this directory as compiled to use
+// the "true" GLES library.
+
 #include "glesgsg.h"
 #include "glstuff_src.cxx"

+ 100 - 0
panda/src/glesgsg/glesgsg.h

@@ -0,0 +1,100 @@
+// Filename: glesgsg.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 GLESGSG_H
+#define GLESGSG_H
+
+// This header file compiles a GSG for the limited subset of OpenGL
+// that is OpenGL ES.
+
+#include "pandabase.h"
+#include "config_glesgsg.h"
+
+#define GLP(name) gl##name
+#define GLUP(name) glu##name
+#define CLP(name) GLES##name
+#define GLPREFIX_QUOTED "gl"
+#define CLASSPREFIX_QUOTED "GLES"
+#define GLSYSTEM_NAME "OpenGL ES"
+#define CONFIGOBJ config_glesgsg
+#define GLCAT glesgsg_cat
+#define EXPCL_GL EXPCL_PANDAGLES
+#define EXPTP_GL EXPTP_PANDAGLES
+#ifndef OPENGLES
+  #define OPENGLES
+#endif
+#ifndef OPENGLES_1
+  #define OPENGLES_1
+#endif
+#ifdef OPENGLES_2
+  #error OPENGLES_2 should not be defined!
+#endif
+
+#ifdef IS_OSX
+  #include <OpenGLES/ES1/gl.h>
+  #include <OpenGLES/ES1/glext.h>
+#else
+  #include <GLES/gl.h>
+  #include <GLES/glext.h>
+#endif
+
+// This helps to keep the source clean of hundreds of #ifdefs.
+#ifdef OPENGLES_1
+  #define GL_NONE GL_NONE_OES
+  #define GL_RENDERBUFFER_EXT GL_RENDERBUFFER_OES
+  #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES
+  #define GL_DRAW_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES
+  #define GL_READ_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES
+  #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0_OES
+  #define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT_OES
+  #define GL_STENCIL_ATTACHMENT_EXT GL_STENCIL_ATTACHMENT_OES
+  #define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE_OES
+  #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES
+  #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES
+  #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES
+  #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES
+  #define GL_FRAMEBUFFER_UNSUPPORTED_EXT GL_FRAMEBUFFER_UNSUPPORTED_OES
+  #define GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT24_OES
+  #define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES
+  #define GL_DEPTH_STENCIL_EXT GL_DEPTH_STENCIL_OES
+  #define GL_UNSIGNED_INT_24_8_EXT GL_UNSIGNED_INT_24_8_OES
+  #define GL_DEPTH24_STENCIL8_EXT GL_DEPTH24_STENCIL8_OES
+  #define GL_DEPTH_COMPONENT16 GL_DEPTH_COMPONENT16_OES
+  #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
+  #define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES
+  #define GL_TEXTURE_CUBE_MAP GL_TEXTURE_CUBE_MAP_OES
+  #define GL_TEXTURE_CUBE_MAP_POSITIVE_X GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES
+  #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES
+  #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES
+  #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES
+  #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES
+  #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES
+  #define GL_MAX_CUBE_MAP_TEXTURE_SIZE GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES
+  #define GL_MIRRORED_REPEAT GL_MIRRORED_REPEAT_OES
+  #define GL_RGB5_A1 GL_RGB5_A1_OES
+  #define GL_RGBA4 GL_RGBA4_OES
+  #define GL_RGB8 GL_RGB8_OES
+  #define GL_RGBA8 GL_RGBA8_OES
+  #define GL_FUNC_ADD GL_FUNC_ADD_OES
+  #define GL_FUNC_SUBTRACT GL_FUNC_SUBTRACT_OES
+  #define GL_FUNC_REVERSE_SUBTRACT GL_FUNC_REVERSE_SUBTRACT_OES
+#endif
+
+#undef SUPPORT_IMMEDIATE_MODE
+#define APIENTRY
+#define APIENTRYP *
+
+#include "glstuff_src.h"
+ 
+#endif  // GLESGSG_H

+ 1 - 0
panda/src/glesgsg/glesgsg_composite.cxx

@@ -0,0 +1 @@
+#include "glesgsg_composite1.cxx"

+ 3 - 0
panda/src/glesgsg/glesgsg_composite1.cxx

@@ -0,0 +1,3 @@
+
+#include "config_glesgsg.cxx"
+#include "glesgsg.cxx"

+ 1 - 3
panda/src/iphonedisplay/Sources.pp

@@ -12,14 +12,12 @@
     framework putil collide pgraph chan text \
     pnmimage pnmimagetypes event effects gobj display \
     mathutil putil express dgraph device tform \
-    linmath pstatclient panda glstuff
+    linmath pstatclient panda glstuff glesgsg
 
   #define SOURCES \
     config_iphonedisplay.h config_iphonedisplay.mm \
     viewController.h viewController.mm \
     eaglView.h eaglView.mm \
-    glesext_shadow.h \
-    glesgsg.h glesgsg.mm \
     iPhoneGraphicsPipe.h iPhoneGraphicsPipe.mm \
     iPhoneGraphicsStateGuardian.h iPhoneGraphicsStateGuardian.mm \
     iPhoneGraphicsWindow.h iPhoneGraphicsWindow.I iPhoneGraphicsWindow.mm

+ 0 - 174
panda/src/iphonedisplay/glesext_shadow.h

@@ -1,174 +0,0 @@
-// Filename: glesext_shadow.h
-// Created by:  drose (09Apr09)
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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."
-//
-////////////////////////////////////////////////////////////////////
-
-// This file is designed to #define the extension symbols that aren't
-// used for OpenGL ES, just so we can compile the glstuff module.
-// These symbols have to be defined, even if they are never actually
-// used at runtime; and it doesn't particularly matter what their
-// defined value is.
-
-#define GL_ACCUM_ALPHA_BITS 0
-#define GL_ACCUM_BLUE_BITS 1
-#define GL_ACCUM_BUFFER_BIT 2
-#define GL_ACCUM_GREEN_BITS 3
-#define GL_ACCUM_RED_BITS 4
-#define GL_AUX_BUFFERS 5
-#define GL_BACK_LEFT 6
-#define GL_BACK_RIGHT 7
-#define GL_BGR 8
-#define GL_BLUE 9
-#define GL_CLAMP 10
-#define GL_CLAMP_TO_BORDER 11
-#define GL_COLOR_ATTACHMENT0_EXT 12
-#define GL_COLOR_ATTACHMENT1_EXT 13
-#define GL_COLOR_INDEX 14
-#define GL_COMPARE_R_TO_TEXTURE_ARB 15
-#define GL_COMPILE 16
-#define GL_COMPILE_AND_EXECUTE 17
-#define GL_COMPRESSED_ALPHA 18
-#define GL_COMPRESSED_LUMINANCE 19
-#define GL_COMPRESSED_LUMINANCE_ALPHA 20
-#define GL_COMPRESSED_RGB 21
-#define GL_COMPRESSED_RGBA 22
-#define GL_COMPRESSED_RGBA_FXT1_3DFX 23
-#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 24
-#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 25
-#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 26
-#define GL_COMPRESSED_RGB_FXT1_3DFX 27
-#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 28
-#define GL_CONSTANT_ALPHA 29
-#define GL_CONSTANT_COLOR 30
-#define GL_COORD_REPLACE_ARB 31
-#define GL_DECR_WRAP 32
-#define GL_DEPTH_ATTACHMENT_EXT 33
-#define GL_DEPTH_COMPONENT 34
-#define GL_DEPTH_STENCIL_EXT 35
-#define GL_DEPTH_TEXTURE_MODE_ARB 36
-#define GL_DOUBLEBUFFER 37
-#define GL_EYE_LINEAR 38
-#define GL_EYE_PLANE 39
-#define GL_FILL 40
-#define GL_FRAMEBUFFER_COMPLETE_EXT 41
-#define GL_FRAMEBUFFER_EXT 42
-#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 43
-#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 44
-#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 45
-#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 46
-#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 47
-#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 48
-#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 49
-#define GL_FRONT_LEFT 50
-#define GL_FRONT_RIGHT 51
-#define GL_FUNC_ADD 52
-#define GL_FUNC_REVERSE_SUBTRACT 53
-#define GL_FUNC_SUBTRACT 54
-#define GL_GREEN 55
-#define GL_INCR_WRAP 56
-#define GL_INDEX_BITS 57
-#define GL_INTENSITY 58
-#define GL_LEFT 59
-#define GL_LIGHT_MODEL_LOCAL_VIEWER 60
-#define GL_LINE 61
-#define GL_MATRIX_INDEX_ARRAY_ARB 62
-#define GL_MATRIX_PALETTE_ARB 63
-#define GL_MAX 64
-#define GL_MAX_3D_TEXTURE_SIZE 65
-#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 66
-#define GL_MAX_DRAW_BUFFERS 67
-#define GL_MAX_ELEMENTS_INDICES 68
-#define GL_MAX_ELEMENTS_VERTICES 69
-#define GL_MAX_PALETTE_MATRICES_ARB 70
-#define GL_MAX_VERTEX_UNITS_ARB 71
-#define GL_MIN 72
-#define GL_MIRRORED_REPEAT 73
-#define GL_MIRROR_CLAMP_EXT 74
-#define GL_MIRROR_CLAMP_TO_BORDER_EXT 75
-#define GL_MIRROR_CLAMP_TO_EDGE_EXT 76
-#define GL_MODELVIEW0_ARB 77
-#define GL_MODELVIEW1_ARB 78
-#define GL_MODELVIEW2_ARB 79
-#define GL_NONE 80
-#define GL_NORMAL_MAP 81
-#define GL_OBJECT_LINEAR 82
-#define GL_OBJECT_PLANE 83
-#define GL_ONE_MINUS_CONSTANT_ALPHA 84
-#define GL_ONE_MINUS_CONSTANT_COLOR 85
-#define GL_POINT 86
-#define GL_POINT_SPRITE_ARB 87
-#define GL_POLYGON_SMOOTH 88
-#define GL_POLYGON_SMOOTH_HINT 89
-#define GL_Q 90
-#define GL_QUERY_COUNTER_BITS 91
-#define GL_R 92
-#define GL_R3_G3_B2 93
-#define GL_RED 94
-#define GL_REFLECTION_MAP 95
-#define GL_RENDERBUFFER_EXT 96
-#define GL_RGB12 97
-#define GL_RGB5 98
-#define GL_RGB5_A1 99
-#define GL_RGB8 100
-#define GL_RGBA12 101
-#define GL_RGBA16F_ARB 102
-#define GL_RGBA32F_ARB 103
-#define GL_RGBA4 104
-#define GL_RGBA8 105
-#define GL_RGBA8_EXT 106
-#define GL_RIGHT 107
-#define GL_S 108
-#define GL_SAMPLES_PASSED 109
-#define GL_SPHERE_MAP 110
-#define GL_STENCIL_ATTACHMENT_EXT 111
-#define GL_STENCIL_TEST_TWO_SIDE_EXT 112
-#define GL_STEREO 113
-#define GL_STREAM_DRAW 114
-#define GL_T 115
-#define GL_TEXTURE_1D 116
-#define GL_TEXTURE_3D 117
-#define GL_TEXTURE_ALPHA_SIZE 118
-#define GL_TEXTURE_BLUE_SIZE 119
-#define GL_TEXTURE_BORDER_COLOR 120
-#define GL_TEXTURE_COMPARE_FUNC_ARB 121
-#define GL_TEXTURE_COMPARE_MODE_ARB 122
-#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 123
-#define GL_TEXTURE_COMPRESSION_HINT 124
-#define GL_TEXTURE_CUBE_MAP 125
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 126
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 127
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 128
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 129
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 130
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 131
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 132
-#define GL_TEXTURE_DEPTH 133
-#define GL_TEXTURE_GEN_MODE 134
-#define GL_TEXTURE_GEN_Q 135
-#define GL_TEXTURE_GEN_R 136
-#define GL_TEXTURE_GEN_S 137
-#define GL_TEXTURE_GEN_T 138
-#define GL_TEXTURE_GREEN_SIZE 139
-#define GL_TEXTURE_HEIGHT 140
-#define GL_TEXTURE_INTENSITY_SIZE 141
-#define GL_TEXTURE_INTERNAL_FORMAT 142
-#define GL_TEXTURE_LUMINANCE_SIZE 143
-#define GL_TEXTURE_MAX_LEVEL 144
-#define GL_TEXTURE_RED_SIZE 145
-#define GL_TEXTURE_WIDTH 146
-#define GL_TEXTURE_WRAP_R 147
-#define GL_UNSIGNED_INT 148
-#define GL_UNSIGNED_INT_24_8_EXT 149
-#define GL_VERTEX_BLEND_ARB 150
-#define GL_WEIGHT_ARRAY_ARB 151
-#define GL_WEIGHT_SUM_UNITY_ARB 152
-#define GL_DEPTH24_STENCIL8_EXT 153

+ 0 - 49
panda/src/iphonedisplay/glesgsg.h

@@ -1,49 +0,0 @@
-// Filename: glesgsg.h
-// Created by:  drose (09Apr09)
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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 GLESGSG_H
-#define GLESGSG_H
-
-// This header file compiles a GSG for the limited subset of OpenGL
-// that is OpenGL ES.
-
-#include "pandabase.h"
-#include "config_iphonedisplay.h"
-
-#define GLP(name) gl##name
-#define GLUP(name) glu##name
-#define CLP(name) GLES##name
-#define GLPREFIX_QUOTED "gl"
-#define CLASSPREFIX_QUOTED "GLES"
-#define GLSYSTEM_NAME "OpenGL ES"
-#define CONFIGOBJ config_iphonedisplay
-#define GLCAT iphonedisplay_cat
-#define EXPCL_GL EXPCL_MISC
-#define EXPTP_GL EXPTP_MISC
-#define OPENGLES
-#define OPENGLES_1
-#undef HAVE_GLU
-
-#include <OpenGLES/ES1/gl.h>
-#include <OpenGLES/ES1/glext.h>
-
-#include "glesext_shadow.h"
-
-#undef SUPPORT_IMMEDIATE_MODE
-#define APIENTRY
-#define APIENTRYP *
-
-#include "glstuff_src.h"
- 
-#endif  // GLESGSG_H

+ 22 - 0
panda/src/pandabase/pandasymbols.h

@@ -120,6 +120,22 @@
   #define EXPTP_PANDAGL extern
 #endif
 
+#ifdef BUILDING_PANDAGLES
+  #define EXPCL_PANDAGLES __declspec(dllexport)
+  #define EXPTP_PANDAGLES
+#else
+  #define EXPCL_PANDAGLES __declspec(dllimport)
+  #define EXPTP_PANDAGLES extern
+#endif
+
+#ifdef BUILDING_PANDAGLES2
+  #define EXPCL_PANDAGLES2 __declspec(dllexport)
+  #define EXPTP_PANDAGLES2
+#else
+  #define EXPCL_PANDAGLES2 __declspec(dllimport)
+  #define EXPTP_PANDAGLES2 extern
+#endif
+
 #ifdef BUILDING_PANDAGLUT
   #define EXPCL_PANDAGLUT __declspec(dllexport)
   #define EXPTP_PANDAGLUT
@@ -246,6 +262,12 @@
 #define EXPCL_PANDAGL
 #define EXPTP_PANDAGL
 
+#define EXPCL_PANDAGLES
+#define EXPTP_PANDAGLES
+
+#define EXPCL_PANDAGLES2
+#define EXPTP_PANDAGLES2
+
 #define EXPCL_PANDAGLUT
 #define EXPTP_PANDAGLUT