Browse Source

better handling of opengl extension pointers

David Rose 16 years ago
parent
commit
0f39a32569

+ 50 - 11
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -106,17 +106,6 @@ get_gl_version_minor() const {
   return _gl_version_minor;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_gl_version_release
-//       Access: Public
-//  Description: Returns the release part of the reported GL version
-//               number.
-////////////////////////////////////////////////////////////////////
-INLINE int CLP(GraphicsStateGuardian)::
-get_gl_version_release() const {
-  return _gl_version_release;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::maybe_gl_finish
 //       Access: Protected
@@ -132,6 +121,56 @@ maybe_gl_finish() const {
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::is_at_least_gl_version
+//       Access: Public
+//  Description: Returns true if we are compiled for mainline OpenGL,
+//               and the runtime GL version number is at least the
+//               indicated value, false otherwise.  Under OpenGL ES,
+//               this always returns false.
+////////////////////////////////////////////////////////////////////
+INLINE bool CLP(GraphicsStateGuardian)::
+is_at_least_gl_version(int major_version, int minor_version) const {
+#ifdef OPENGLES_1
+  return false;
+#else
+  if (_gl_version_major < major_version) {
+    return false;
+  } else if (_gl_version_major == major_version) {
+    if (_gl_version_minor < minor_version) {
+      return false;
+    }
+  }
+
+  return true;
+#endif  // OPENGLES_1
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::is_at_least_gles_version
+//       Access: Public
+//  Description: Returns true if we are compiled for OpenGL ES,
+//               and the runtime GL ES version number is at least the
+//               indicated value, false otherwise.  Under mainline
+//               OpenGL, this always returns false.
+////////////////////////////////////////////////////////////////////
+INLINE bool CLP(GraphicsStateGuardian)::
+is_at_least_gles_version(int major_version, int minor_version) const {
+#ifndef OPENGLES_1
+  return false;
+#else
+  if (_gl_version_major < major_version) {
+    return false;
+  } else if (_gl_version_major == major_version) {
+    if (_gl_version_minor < minor_version) {
+      return false;
+    }
+  }
+
+  return true;
+#endif  // OPENGLES_1
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::enable_multisample_antialias
 //       Access: Protected

+ 144 - 167
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -352,18 +352,10 @@ reset() {
 
   _supports_point_parameters = false;
 
-  if (is_at_least_version(1, 4)) {
+  if (is_at_least_gl_version(1, 4)) {
     _supports_point_parameters = true;
-#ifdef EXPECT_GL_VERSION_1_4
-    GLCAT.debug()
-      << "Getting compile-time PointParameter pointers\n";
-    _glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)&GLP(PointParameterfv);
-#else  // EXPECT_GL_VERSION_1_4
-    GLCAT.debug()
-      << "Getting run-time PointParameter pointers\n";
     _glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)
       get_extension_func(GLPREFIX_QUOTED, "PointParameterfv");
-#endif  // EXPECT_GL_VERSION_1_4
 
   } else if (has_extension("GL_ARB_point_parameters")) {
     _supports_point_parameters = true;
@@ -471,18 +463,10 @@ reset() {
 
   _supports_draw_range_elements = false;
 
-  if (is_at_least_version(1, 2)) {
+  if (is_at_least_gl_version(1, 2)) {
     _supports_draw_range_elements = true;
-#ifdef EXPECT_GL_VERSION_1_2
-    GLCAT.debug()
-      << "Getting compile-time DrawRangeElements pointers\n";
-    _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)&GLP(DrawRangeElements);
-#else  // EXPECT_GL_VERSION_1_2
-    GLCAT.debug()
-      << "Getting run-time DrawRangeElements pointers\n";
     _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)
       get_extension_func(GLPREFIX_QUOTED, "DrawRangeElements");
-#endif  // EXPECT_GL_VERSION_1_2
 
   } else if (has_extension("GL_EXT_draw_range_elements")) {
     _supports_draw_range_elements = true;
@@ -501,7 +485,7 @@ reset() {
   }
 
   _supports_depth_texture =
-    has_extension("GL_ARB_depth_texture") || is_at_least_version(1, 4);
+    has_extension("GL_ARB_depth_texture") || is_at_least_gl_version(1, 4);
 
   _supports_depth_stencil = false;
   if (_supports_depth_texture) {
@@ -511,22 +495,13 @@ reset() {
   
   _supports_3d_texture = false;
 
-  if (is_at_least_version(1, 2)) {
+  if (is_at_least_gl_version(1, 2)) {
     _supports_3d_texture = true;
 
-#ifdef EXPECT_GL_VERSION_1_2
-    GLCAT.debug()
-      << "Getting compile-time 3-D textures pointers\n";
-    _glTexImage3D = (PFNGLTEXIMAGE3DPROC)&GLP(TexImage3D);
-    _glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)&GLP(TexSubImage3D);
-#else  // EXPECT_GL_VERSION_1_2
-    GLCAT.debug()
-      << "Getting run-time 3-D textures pointers\n";
     _glTexImage3D = (PFNGLTEXIMAGE3DPROC)
       get_extension_func(GLPREFIX_QUOTED, "TexImage3D");
     _glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)
       get_extension_func(GLPREFIX_QUOTED, "TexSubImage3D");
-#endif  // EXPECT_GL_VERSION_1_2
 
   } else if (has_extension("GL_EXT_texture3D")) {
     _supports_3d_texture = true;
@@ -546,25 +521,13 @@ reset() {
   }
 
   _supports_cube_map =
-    has_extension("GL_ARB_texture_cube_map") || is_at_least_version(1, 3);
+    has_extension("GL_ARB_texture_cube_map") || is_at_least_gl_version(1, 3);
 
   _supports_compressed_texture = false;
-  if (is_at_least_version(1, 3)) {
+
+  if (is_at_least_gl_version(1, 3)) {
     _supports_compressed_texture = true;
 
-#ifdef EXPECT_GL_VERSION_1_3
-    GLCAT.debug()
-      << "Getting compile-time compressed textures pointers\n";
-    _glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)&GLP(CompressedTexImage1D);
-    _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)&GLP(CompressedTexImage2D);
-    _glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)&GLP(CompressedTexImage3D);
-    _glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)&GLP(CompressedTexSubImage1D);
-    _glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)&GLP(CompressedTexSubImage2D);
-    _glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)&GLP(CompressedTexSubImage3D);
-    _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)&GLP(GetCompressedTexImage);
-#else  // EXPECT_GL_VERSION_1_3
-    GLCAT.debug()
-      << "Getting run-time compressed textures pointers\n";
     _glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexImage1D");
     _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)
@@ -579,7 +542,6 @@ reset() {
       get_extension_func(GLPREFIX_QUOTED, "CompressedTexSubImage3D");
     _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
       get_extension_func(GLPREFIX_QUOTED, "GetCompressedTexImage");
-#endif  // EXPECT_GL_VERSION_1_3
 
   } else if (has_extension("GL_ARB_texture_compression")) {
     _supports_compressed_texture = true;
@@ -649,17 +611,17 @@ reset() {
   }
 
   _supports_bgr =
-    has_extension("GL_EXT_bgra") || is_at_least_version(1, 2);
+    has_extension("GL_EXT_bgra") || is_at_least_gl_version(1, 2);
 
   _supports_rescale_normal =
     CLP(support_rescale_normal) &&
-    (has_extension("GL_EXT_rescale_normal") || is_at_least_version(1, 2));
+    (has_extension("GL_EXT_rescale_normal") || is_at_least_gl_version(1, 2));
 
   _supports_multisample =
     has_extension("GL_ARB_multisample");
 
   _supports_generate_mipmap =
-    has_extension("GL_SGIS_generate_mipmap") || is_at_least_version(1, 4);
+    has_extension("GL_SGIS_generate_mipmap") || is_at_least_gl_version(1, 4) || is_at_least_gles_version(1, 1);
 
   _supports_multitexture = false;
 
@@ -671,22 +633,9 @@ reset() {
   _supports_tex_non_pow2 =
     has_extension("GL_ARB_texture_non_power_of_two");
 
-  if (is_at_least_version(1, 3)) {
+  if (is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1)) {
     _supports_multitexture = true;
 
-#ifdef EXPECT_GL_VERSION_1_3
-    GLCAT.debug()
-      << "Getting compile-time multitexture pointers\n";
-    _glActiveTexture = (PFNGLACTIVETEXTUREPROC)&GLP(ActiveTexture);
-    _glClientActiveTexture = (PFNGLACTIVETEXTUREPROC)&GLP(ClientActiveTexture);
-    _glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)&GLP(MultiTexCoord1f);
-    _glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)&GLP(MultiTexCoord2f);
-    _glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)&GLP(MultiTexCoord3f);
-    _glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)&GLP(MultiTexCoord4f);
-
-#else  // EXPECT_GL_VERSION_1_3
-    GLCAT.debug() 
-      << "Getting run-time multitexture pointers\n";
     _glActiveTexture = (PFNGLACTIVETEXTUREPROC)
       get_extension_func(GLPREFIX_QUOTED, "ActiveTexture");
     _glClientActiveTexture = (PFNGLACTIVETEXTUREPROC)
@@ -699,7 +648,6 @@ reset() {
       get_extension_func(GLPREFIX_QUOTED, "MultiTexCoord3f");
     _glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)
       get_extension_func(GLPREFIX_QUOTED, "MultiTexCoord4f");
-#endif  // EXPECT_GL_VERSION_1_3
 
   } else if (has_extension("GL_ARB_multitexture")) {
     _supports_multitexture = true;
@@ -719,9 +667,12 @@ reset() {
   }
 
   if (_supports_multitexture) {
-    if (_glActiveTexture == NULL || _glClientActiveTexture == NULL ||
-        _glMultiTexCoord1f == NULL || _glMultiTexCoord2f == NULL ||
-        _glMultiTexCoord3f == NULL || _glMultiTexCoord4f == NULL) {
+    if (_glActiveTexture == NULL || _glClientActiveTexture == NULL
+#ifdef SUPPORT_IMMEDIATE_MODE
+        || _glMultiTexCoord1f == NULL || _glMultiTexCoord2f == NULL
+        || _glMultiTexCoord3f == NULL || _glMultiTexCoord4f == NULL
+#endif
+        ) {
       GLCAT.warning()
         << "Multitexture advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
       _supports_multitexture = false;
@@ -747,28 +698,17 @@ reset() {
   }
   
   _supports_texture_combine =
-    has_extension("GL_ARB_texture_env_combine") || is_at_least_version(1, 3);
+    has_extension("GL_ARB_texture_env_combine") || is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1);
   _supports_texture_saved_result =
-    has_extension("GL_ARB_texture_env_crossbar") || is_at_least_version(1, 4);
+    has_extension("GL_ARB_texture_env_crossbar") || is_at_least_gl_version(1, 4);
   _supports_texture_dot3 =
-    has_extension("GL_ARB_texture_env_dot3") || is_at_least_version(1, 3);
+    has_extension("GL_ARB_texture_env_dot3") || is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1);
 
   _supports_buffers = false;
 
-  if (is_at_least_version(1, 5)) {
+  if (is_at_least_gl_version(1, 5) || is_at_least_gles_version(1, 1)) {
     _supports_buffers = true;
 
-#ifdef EXPECT_GL_VERSION_1_5
-    GLCAT.debug()
-      << "Getting compile-time buffer pointers\n";
-    _glGenBuffers = (PFNGLGENBUFFERSPROC)&GLP(GenBuffers);
-    _glBindBuffer = (PFNGLBINDBUFFERPROC)&GLP(BindBuffer);
-    _glBufferData = (PFNGLBUFFERDATAPROC)&GLP(BufferData);
-    _glBufferSubData = (PFNGLBUFFERSUBDATAPROC)&GLP(BufferSubData);
-    _glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)&GLP(DeleteBuffers);
-#else  // EXPECT_GL_VERSION_1_5
-    GLCAT.debug()
-      << "Getting run-time buffer pointers\n";
     _glGenBuffers = (PFNGLGENBUFFERSPROC)
       get_extension_func(GLPREFIX_QUOTED, "GenBuffers");
     _glBindBuffer = (PFNGLBINDBUFFERPROC)
@@ -779,7 +719,6 @@ reset() {
       get_extension_func(GLPREFIX_QUOTED, "BufferSubData");
     _glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)
       get_extension_func(GLPREFIX_QUOTED, "DeleteBuffers");
-#endif  // EXPECT_GL_VERSION_1_5
 
   } else if (has_extension("GL_ARB_vertex_buffer_object")) {
     _supports_buffers = true;
@@ -870,7 +809,7 @@ reset() {
   }
 
   _glDrawBuffers = NULL;
-  if (is_at_least_version(2, 0)) {
+  if (is_at_least_gl_version(2, 0)) {
     _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
       get_extension_func(GLPREFIX_QUOTED, "DrawBuffers");
   } else if (has_extension("GL_ARB_draw_buffers")) {
@@ -887,22 +826,9 @@ reset() {
 
   _supports_occlusion_query = false;
   if (CLP(support_occlusion_query)) {
-    if (is_at_least_version(1, 5)) {
+    if (is_at_least_gl_version(1, 5)) {
       _supports_occlusion_query = true;
 
-#ifdef EXPECT_GL_VERSION_1_5
-      GLCAT.debug()
-        << "Getting compile-time occlusion pointers\n";
-      _glGenQueries = (PFNGLGENQUERIESPROC)&GLP(GenQueries);
-      _glBeginQuery = (PFNGLBEGINQUERYPROC)&GLP(BeginQuery);
-      _glEndQuery = (PFNGLENDQUERYPROC)&GLP(EndQuery);
-      _glDeleteQueries = (PFNGLDELETEQUERIESPROC)&GLP(DeleteQueries);
-      _glGetQueryiv = (PFNGLGETQUERYIVPROC)&GLP(GetQueryiv);
-      _glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)&GLP(GetQueryObjectuiv);
-
-#else  // EXPECT_GL_VERSION_1_5
-      GLCAT.debug()
-        << "Getting run-time occlusion pointers\n";
       _glGenQueries = (PFNGLGENQUERIESPROC)
         get_extension_func(GLPREFIX_QUOTED, "GenQueries");
       _glBeginQuery = (PFNGLBEGINQUERYPROC)
@@ -915,7 +841,6 @@ reset() {
         get_extension_func(GLPREFIX_QUOTED, "GetQueryiv");
       _glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)
         get_extension_func(GLPREFIX_QUOTED, "GetQueryObjectuiv");
-#endif  // EXPECT_GL_VERSION_1_5
 
     } else if (has_extension("GL_ARB_occlusion_query")) {
       _supports_occlusion_query = true;
@@ -956,18 +881,10 @@ reset() {
 
   _glBlendEquation = NULL;
   bool supports_blend_equation = false;
-  if (is_at_least_version(1, 2)) {
+  if (is_at_least_gl_version(1, 2)) {
     supports_blend_equation = true;
-#ifdef EXPECT_GL_VERSION_1_2
-    GLCAT.debug()
-      << "Getting compile-time BlendEquation pointers\n";
-    _glBlendEquation = (PFNGLBLENDEQUATIONPROC)&GLP(BlendEquation);
-#else  // EXPECT_GL_VERSION_1_2
-    GLCAT.debug()
-      << "Getting run-time blend pointers\n";
     _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
       get_extension_func(GLPREFIX_QUOTED, "BlendEquation");
-#endif  // EXPECT_GL_VERSION_1_2
   } else if (has_extension("GL_EXT_blend_minmax")) {
     supports_blend_equation = true;
     _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
@@ -983,18 +900,10 @@ reset() {
 
   _glBlendColor = NULL;
   bool supports_blend_color = false;
-  if (is_at_least_version(1, 2)) {
+  if (is_at_least_gl_version(1, 2)) {
     supports_blend_color = true;
-#ifdef EXPECT_GL_VERSION_1_2
-    GLCAT.debug()
-      << "Getting compile-time BlendColor pointers\n";
-    _glBlendColor = (PFNGLBLENDCOLORPROC)&GLP(BlendColor);
-#else  // EXPECT_GL_VERSION_1_2
-    GLCAT.debug()
-      << "Getting run-time BlendColor pointers\n";
     _glBlendColor = (PFNGLBLENDCOLORPROC)
       get_extension_func(GLPREFIX_QUOTED, "BlendColor");
-#endif  // EXPECT_GL_VERSION_1_2
   } else if (has_extension("GL_EXT_blend_color")) {
     supports_blend_color = true;
     _glBlendColor = (PFNGLBLENDCOLORPROC)
@@ -1008,30 +917,27 @@ reset() {
     _glBlendColor = null_glBlendColor;
   }
 
-#ifdef OPENGLES_1
-  _edge_clamp = GL_REPEAT;
-#else
   _edge_clamp = GL_CLAMP;
-#endif
   if (has_extension("GL_SGIS_texture_edge_clamp") ||
-      is_at_least_version(1, 2)) {
+      is_at_least_gl_version(1, 2) || is_at_least_gles_version(1, 1)) {
     _edge_clamp = GL_CLAMP_TO_EDGE;
   }
 
   _border_clamp = _edge_clamp;
   if (CLP(support_clamp_to_border) &&
       (has_extension("GL_ARB_texture_border_clamp") ||
-       is_at_least_version(1, 3))) {
+       is_at_least_gl_version(1, 3))) {
     _border_clamp = GL_CLAMP_TO_BORDER;
   }
 
   _mirror_repeat = GL_REPEAT;
   if (has_extension("GL_ARB_texture_mirrored_repeat") ||
-      is_at_least_version(1, 4)) {
+      is_at_least_gl_version(1, 4) ||
+      has_extension("GL_OES_texture_mirrored_repeat")) {
     _mirror_repeat = GL_MIRRORED_REPEAT;
   }
 
-  _mirror_clamp = GL_CLAMP;
+  _mirror_clamp = _edge_clamp;
   _mirror_edge_clamp = _edge_clamp;
   _mirror_border_clamp = _border_clamp;
   if (has_extension("GL_EXT_texture_mirror_clamp")) {
@@ -1469,7 +1375,9 @@ clear(DrawableRegion *clearable) {
   }
   
   if (clearable->get_clear_depth_active()) {
-#ifndef OPENGLES_1  // Temporary: need glClearDepthf() instead for OpenGL ES.
+#ifdef OPENGLES_1
+    GLP(ClearDepthf)(clearable->get_clear_depth());
+#else
     GLP(ClearDepth)(clearable->get_clear_depth());
 #endif  // OPENGLES_1
     GLP(DepthMask)(GL_TRUE);
@@ -4681,11 +4589,9 @@ void CLP(GraphicsStateGuardian)::
 query_gl_version() {
   _gl_vendor = show_gl_string("GL_VENDOR", GL_VENDOR);
   _gl_renderer = show_gl_string("GL_RENDERER", GL_RENDERER);
-  _gl_version = show_gl_string("GL_VERSION", GL_VERSION);
 
   _gl_version_major = 0;
   _gl_version_minor = 0;
-  _gl_version_release = 0;
 
   const GLubyte *text = GLP(GetString)(GL_VERSION);
   if (text == (const GLubyte *)NULL) {
@@ -4693,8 +4599,24 @@ query_gl_version() {
       << "Unable to query GL_VERSION\n";
   } else {
     string version((const char *)text);
+    _gl_version = version;
 
     string input = version;
+
+    // Skip any initial words that don't begin with a digit.
+    while (!input.empty() && !isdigit(input[0])) {
+      size_t space = input.find(' ');
+      if (space == string::npos) {
+        break;
+      }
+      size_t next = space + 1;
+      while (next < input.length() && isspace(input[next])) {
+        ++next;
+      }
+      input = input.substr(next);
+    }
+
+    // Truncate after the first space.
     size_t space = input.find(' ');
     if (space != string::npos) {
       input = input.substr(0, space);
@@ -4708,15 +4630,12 @@ query_gl_version() {
     if (components.size() >= 2) {
       string_to_int(components[1], _gl_version_minor);
     }
-    if (components.size() >= 3) {
-      string_to_int(components[2], _gl_version_release);
-    }
 
     if (GLCAT.is_debug()) {
       GLCAT.debug()
         << "GL_VERSION = " << version << ", decoded to "
         << _gl_version_major << "." << _gl_version_minor
-        << "." << _gl_version_release << "\n";
+        << "\n";
     }
   }
 }
@@ -4793,41 +4712,98 @@ has_extension(const string &extension) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::is_at_least_version
+//     Function: GLGraphicsStateGuardian::get_extension_func
 //       Access: Public
-//  Description: Returns true if the runtime GL version number is at
-//               least the indicated value, false otherwise.
+//  Description: Returns the pointer to the GL extension function with
+//               the indicated name, or NULL if the function is not
+//               available.
 ////////////////////////////////////////////////////////////////////
-bool CLP(GraphicsStateGuardian)::
-is_at_least_version(int major_version, int minor_version,
-                    int release_version) const {
-  if (_gl_version_major < major_version) {
-    return false;
-  } else if (_gl_version_major == major_version) {
-    if (_gl_version_minor < minor_version) {
-      return false;
-    } else if (_gl_version_minor == minor_version) {
-      if (_gl_version_release < release_version) {
-        return false;
-      }
+void *CLP(GraphicsStateGuardian)::
+get_extension_func(const char *prefix, const char *name) {
+  // First, look in the static-compiled namespace.  If we were
+  // compiled to expect at least a certain minimum runtime version of
+  // OpenGL, then we can expect those extension functions to be
+  // available at compile time.  Somewhat more reliable than poking
+  // around in the runtime pointers.
+  static struct {
+    const char *name;
+    void *fptr;
+  } compiled_function_table[] = {
+#ifdef EXPECT_GL_VERSION_1_2
+    { "BlendColor", (void *)&GLP(BlendColor) },
+    { "BlendEquation", (void *)&GLP(BlendEquation) },
+    { "DrawRangeElements", (void *)&GLP(DrawRangeElements) },
+    { "TexImage3D", (void *)&GLP(TexImage3D) },
+    { "TexSubImage3D", (void *)&GLP(TexSubImage3D) },
+#endif
+#ifdef EXPECT_GL_VERSION_1_3
+    { "ActiveTexture", (void *)&GLP(ActiveTexture) },
+    { "ClientActiveTexture", (void *)&GLP(ClientActiveTexture) },
+    { "CompressedTexImage1D", (void *)&GLP(CompressedTexImage1D) },
+    { "CompressedTexImage2D", (void *)&GLP(CompressedTexImage2D) },
+    { "CompressedTexImage3D", (void *)&GLP(CompressedTexImage3D) },
+    { "CompressedTexSubImage1D", (void *)&GLP(CompressedTexSubImage1D) },
+    { "CompressedTexSubImage2D", (void *)&GLP(CompressedTexSubImage2D) },
+    { "CompressedTexSubImage3D", (void *)&GLP(CompressedTexSubImage3D) },
+    { "GetCompressedTexImage", (void *)&GLP(GetCompressedTexImage) },
+    { "MultiTexCoord1f", (void *)&GLP(MultiTexCoord1f) },
+    { "MultiTexCoord2f", (void *)&GLP(MultiTexCoord2f) },
+    { "MultiTexCoord3f", (void *)&GLP(MultiTexCoord3f) },
+    { "MultiTexCoord4f", (void *)&GLP(MultiTexCoord4f) },
+#endif
+#ifdef EXPECT_GL_VERSION_1_4
+    { "PointParameterfv", (void *)&GLP(PointParameterfv) },
+#endif
+#ifdef EXPECT_GL_VERSION_1_5
+    { "BeginQuery", (void *)&GLP(BeginQuery) },
+    { "BindBuffer", (void *)&GLP(BindBuffer) },
+    { "BufferData", (void *)&GLP(BufferData) },
+    { "BufferSubData", (void *)&GLP(BufferSubData) },
+    { "DeleteBuffers", (void *)&GLP(DeleteBuffers) },
+    { "DeleteQueries", (void *)&GLP(DeleteQueries) },
+    { "EndQuery", (void *)&GLP(EndQuery) },
+    { "GenBuffers", (void *)&GLP(GenBuffers) },
+    { "GenQueries", (void *)&GLP(GenQueries) },
+    { "GetQueryObjectuiv", (void *)&GLP(GetQueryObjectuiv) },
+    { "GetQueryiv", (void *)&GLP(GetQueryiv) },
+#endif
+#ifdef OPENGLES_1
+    { "ActiveTexture", (void *)&GLP(ActiveTexture) },
+    { "ClientActiveTexture", (void *)&GLP(ClientActiveTexture) },
+    { "BindBuffer", (void *)&GLP(BindBuffer) },
+    { "BufferData", (void *)&GLP(BufferData) },
+    { "BufferSubData", (void *)&GLP(BufferSubData) },
+    { "DeleteBuffers", (void *)&GLP(DeleteBuffers) },
+    { "GenBuffers", (void *)&GLP(GenBuffers) },
+#endif
+    { NULL, NULL }
+  };
+
+  int i = 0;
+  while (compiled_function_table[i].name != NULL) {
+    if (strcmp(compiled_function_table[i].name, name) == 0) {
+      return compiled_function_table[i].fptr;
     }
+    ++i;
   }
 
-  return true;
+  // If the extension function wasn't compiled in, then go get it from
+  // the runtime.  There's a different interface for each API.
+  return do_get_extension_func(prefix, name);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_extension_func
+//     Function: GLGraphicsStateGuardian::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.
+//  Description: This is the virtual implementation of
+//               get_extension_func().  Each API-specific GL
+//               implementation will map this method to the
+//               appropriate API call to retrieve the extension
+//               function pointer.  Returns NULL if the function is
+//               not available.
 ////////////////////////////////////////////////////////////////////
 void *CLP(GraphicsStateGuardian)::
-get_extension_func(const char *, const char *) {
+do_get_extension_func(const char *, const char *) {
   return NULL;
 }
 
@@ -6163,7 +6139,11 @@ bind_clip_plane(const NodePath &plane, int plane_id) {
   DCAST_INTO_V(plane_node, plane.node());
   Planef xformed_plane = plane_node->get_plane() * transform->get_mat();
 
-#ifndef OPENGLES_1  // Temporary: need glClipPlanef() instead for OpenGL ES.
+#ifdef OPENGLES_1
+  // OpenGL ES uses a single-precision call.
+  GLP(ClipPlanef)(id, xformed_plane.get_data());
+#else
+  // Mainline OpenGL uses a double-precision call.
   Planed double_plane(LCAST(double, xformed_plane));
   GLP(ClipPlane)(id, double_plane.get_data());
 #endif  // OPENGLES_1
@@ -7015,10 +6995,6 @@ do_issue_tex_matrix() {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 do_issue_tex_gen() {
-#ifdef OPENGLES_1
-  // Temporary hack
-  return;
-#endif  // OPENGLES_1
   bool force_normal = false;
 
   nassertv(_num_active_texture_stages <= _max_texture_stages);
@@ -7040,15 +7016,16 @@ do_issue_tex_gen() {
   for (int i = 0; i < _num_active_texture_stages; i++) {
     TextureStage *stage = _target_texture->get_on_ff_stage(i);
     _glActiveTexture(GL_TEXTURE0 + i);
-    GLP(Disable)(GL_TEXTURE_GEN_S);
-    GLP(Disable)(GL_TEXTURE_GEN_T);
-    GLP(Disable)(GL_TEXTURE_GEN_R);
-    GLP(Disable)(GL_TEXTURE_GEN_Q);
     if (_supports_point_sprite) {
       GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
     }
 
 #ifndef OPENGLES_1  // TexGen not supported by OpenGL ES.
+    GLP(Disable)(GL_TEXTURE_GEN_S);
+    GLP(Disable)(GL_TEXTURE_GEN_T);
+    GLP(Disable)(GL_TEXTURE_GEN_R);
+    GLP(Disable)(GL_TEXTURE_GEN_Q);
+
     TexGenAttrib::Mode mode = _target_tex_gen->get_mode(stage);
     switch (mode) {
     case TexGenAttrib::M_off:
@@ -7995,7 +7972,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
     }
   }
 
-  if (is_at_least_version(1, 2)) {
+  if (is_at_least_gl_version(1, 2)) {
     if (load_ram_mipmaps) {
       // By the time we get here, we have successfully loaded a certain
       // number of mipmap levels.  Tell the GL that's all it's going to
@@ -8063,7 +8040,7 @@ upload_simple_texture(CLP(TextureContext) *gtc) {
 
   // Turn off mipmaps for the simple texture.
   if (tex->uses_mipmaps()) {
-    if (is_at_least_version(1, 2)) {
+    if (is_at_least_gl_version(1, 2)) {
       GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
     }
   }
@@ -8455,7 +8432,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
     // Also get the mipmap levels.
     GLint num_expected_levels = tex->get_expected_num_mipmap_levels();
     GLint highest_level = num_expected_levels;
-    if (is_at_least_version(1, 2)) {
+    if (is_at_least_gl_version(1, 2)) {
       GLP(GetTexParameteriv)(target, GL_TEXTURE_MAX_LEVEL, &highest_level);
       highest_level = min(highest_level, num_expected_levels);
     }

+ 5 - 4
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -216,7 +216,6 @@ public:
   INLINE const string &get_gl_version() const;
   INLINE int get_gl_version_major() const;
   INLINE int get_gl_version_minor() const;
-  INLINE int get_gl_version_release() const;
 
   virtual void set_state_and_transform(const RenderState *state,
                                        const TransformState *transform);
@@ -258,8 +257,10 @@ protected:
   virtual void get_extra_extensions();
   void report_extensions() const;
   bool has_extension(const string &extension) const;
-  bool is_at_least_version(int major_version, int minor_version, int release_version = 0) const;
-  virtual void *get_extension_func(const char *prefix, const char *name);
+  INLINE bool is_at_least_gl_version(int major_version, int minor_version) const;
+  INLINE bool is_at_least_gles_version(int major_version, int minor_version) const;
+  void *get_extension_func(const char *prefix, const char *name);
+  virtual void *do_get_extension_func(const char *prefix, const char *name);
 
   virtual void reissue_transforms();
   virtual void enable_lighting(bool enable);
@@ -429,7 +430,7 @@ protected:
   string _gl_vendor;
   string _gl_renderer;
   string _gl_version;
-  int _gl_version_major, _gl_version_minor, _gl_version_release;
+  int _gl_version_major, _gl_version_minor;
   pset<string> _extensions;
 
 public:

+ 2 - 2
panda/src/glxdisplay/glxGraphicsStateGuardian.cxx

@@ -462,7 +462,7 @@ get_extra_extensions() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: glxGraphicsStateGuardian::get_extension_func
+//     Function: glxGraphicsStateGuardian::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
@@ -472,7 +472,7 @@ get_extra_extensions() {
 //               not defined.
 ////////////////////////////////////////////////////////////////////
 void *glxGraphicsStateGuardian::
-get_extension_func(const char *prefix, const char *name) {
+do_get_extension_func(const char *prefix, const char *name) {
   string fullname = string(prefix) + string(name);
 
   if (glx_get_proc_address) {

+ 1 - 1
panda/src/glxdisplay/glxGraphicsStateGuardian.h

@@ -113,7 +113,7 @@ protected:
 
   virtual void query_gl_version();
   virtual void get_extra_extensions();
-  virtual void *get_extension_func(const char *prefix, const char *name);
+  virtual void *do_get_extension_func(const char *prefix, const char *name);
 
 private:
   void *get_system_func(const char *name);

+ 9 - 7
panda/src/iphone/ipfreeze.py

@@ -25,7 +25,8 @@ if __name__ == '__main__':
     freezer = FreezeTool.Freezer()
 
     basename = 'iphone_runappmf'
-    link_all_static = True
+    #link_all_static = True
+    link_all_static = False
     
     try:
         opts, args = getopt.getopt(sys.argv[1:], 'h')
@@ -39,8 +40,8 @@ if __name__ == '__main__':
     main = open('iphone_runappmf_src.mm', 'r').read()
     freezer.mainInitCode = main
 
-    #target = 'sim'
-    target = 'phone'
+    target = 'sim'
+    #target = 'phone'
 
     if target == 'sim':
         platform = 'IPhoneSimulator'
@@ -60,8 +61,8 @@ if __name__ == '__main__':
         arch = ' -arch armv6 -mcpu=arm1176jzf-s -miphoneos-version-min=2.0'
     lflags = sysroot
 
-    ipath = '-I/Users/drose/Python-2.5.4.%s/Include -I/Users/drose/Python-2.5.4.%s -I/usr/local/panda/%s/include' % (target, target, target)
-    lpath = '-L/Users/drose/Python-2.5.4.%s -L/usr/local/panda/%s/lib' % (target, target)
+    ipath = '-I/Users/drose/thirdparty.%s/Python-2.5.4/Include -I/Users/drose/thirdparty.%s/Python-2.5.4 -I/usr/local/panda/%s/include' % (target, target, target)
+    lpath = '-L/Users/drose/thirdparty.%s/Python-2.5.4 -L/usr/local/panda/%s/lib' % (target, target)
     libs = ''
     libs += ' -framework Foundation -framework UIKit'
     if link_all_static:
@@ -72,14 +73,15 @@ if __name__ == '__main__':
         libs += ' -framework QuartzCore -framework OpenGLES'
     libs += ' -lpython2.5'
 
-    lpath += ' -L/Users/drose/iphone_thirdparty/lib'
-    libs += ' -ljpeg -lrfftw -lfftw'
+    lpath += ' -L/Users/drose/thirdparty.%s/lib' % (target)
+    #libs += ' -ljpeg -lrfftw -lfftw'
 
     freezer.sourceExtension = '.mm'
     freezer.compileObj = '%s -c %s %s -o %%(basename)s.o %s %%(filename)s' % (cc, arch, cflags, ipath)
     freezer.linkExe = "%s %s %s -o %%(basename)s %s %s %%(basename)s.o" % (cc, arch, lflags, lpath, libs)
 
     freezer.addModule('direct.*.*')
+    freezer.addModule('direct.showbase.RunAppMF')
     freezer.excludeModule('direct.extensions.*')
     freezer.compileToExe = True
     freezer.done()

+ 129 - 5
panda/src/iphone/iphone_runappmf_src.mm

@@ -15,6 +15,7 @@
 #import <UIKit/UIKit.h> 
 #include <fcntl.h>
 #include <iostream>
+#include <unistd.h>
 using namespace std;
 
 #include "pnotify.h"
@@ -52,6 +53,21 @@ extern "C" void initlibdirect();
 int startup = 0;
 
 - (void)applicationDidFinishLaunching: (UIApplication *)application { 
+
+  // Get the App bundle directory.
+  NSBundle *bundle = [NSBundle mainBundle];
+  if (bundle != nil) {
+    app_directory = [bundle bundlePath];
+  }
+
+  // Set this as the current directory.  Not only is this convenient,
+  // but it also makes shared-library linking work.
+  const char *app_directory_cstr = [app_directory cStringUsingEncoding: NSASCIIStringEncoding];
+  int cd = chdir(app_directory_cstr);
+  if (cd < 0) {
+    perror("chdir");
+  }
+
 #ifdef LINK_ALL_STATIC
   // Ensure that all the relevant Panda modules are initialized.
   extern void init_libpanda();
@@ -62,11 +78,6 @@ int startup = 0;
   init_libiphonedisplay();
 #endif
 
-  NSBundle *bundle = [NSBundle mainBundle];
-  if (bundle != nil) {
-    app_directory = [bundle bundlePath];
-  }
-
   animationInterval = 1.0 / 60.0;
   [self startAnimation];
 } 
@@ -233,6 +244,117 @@ int startup = 0;
 
 extern "C" int main(int argc, char *argv[]);
 
+int quickstart() {
+#ifdef LINK_ALL_STATIC
+  // Ensure that all the relevant Panda modules are initialized.
+  extern void init_libpanda();
+  init_libpanda();
+
+  // Ensure the IPhoneDisplay is available.
+  extern void init_libiphonedisplay();
+  init_libiphonedisplay();
+#endif
+
+  NSString *app_directory;
+  NSBundle *bundle = [NSBundle mainBundle];
+  if (bundle != nil) {
+    app_directory = [bundle bundlePath];
+  }
+
+  {
+    Py_FrozenFlag = 1; /* Suppress errors from getpath.c */
+    NSString *app_pathname = [app_directory stringByAppendingString: @"/iphone_runappmf" ];
+    const char *app_pathname_cstr = [app_pathname cStringUsingEncoding: NSASCIIStringEncoding];
+    Py_SetProgramName((char *)app_pathname_cstr);
+    Py_Initialize();
+
+    int argv = 1;
+    NSString *script_pathname = [app_directory stringByAppendingString: @"/iphone.mf" ];
+    const char *script_pathname_cstr = [script_pathname cStringUsingEncoding: NSASCIIStringEncoding];
+    char *argc[] = { (char *)script_pathname_cstr, NULL };
+    PySys_SetArgv(argv, argc);
+
+    const char *app_directory_cstr = [app_directory cStringUsingEncoding: NSASCIIStringEncoding];
+    Py_SetPythonHome((char *)app_directory_cstr);
+
+#ifdef LINK_ALL_STATIC
+    // Construct the Python modules for the interrogate-generated data
+    // we know we've already linked in.
+    initlibpandaexpress();
+    initlibpanda();
+    initlibpandaphysics();
+    initlibpandafx();
+    initlibdirect();
+#endif  // LINK_ALL_STATIC
+
+#if 0
+    PyImport_ImportFrozenModule("direct");
+    PyImport_ImportFrozenModule("direct.showbase");
+    int n = PyImport_ImportFrozenModule("direct.showbase.RunAppMF");
+    if (n == 0) {
+      cerr << "RunAppMF not frozen in binary\n";
+      Py_Finalize();
+      exit(1);
+    } else if (n < 0) {
+      PyErr_Print();
+      Py_Finalize();
+      exit(1);
+    }
+#endif
+  }
+  {
+    PyObject *module = PyImport_ImportModule("direct");
+    if (module == (PyObject *)NULL) {
+      cerr << "direct not importable\n";
+      PyErr_Print();
+      Py_Finalize();
+      exit(1);
+    }
+    Py_DECREF(module);
+
+    module = PyImport_ImportModule("direct.showbase");
+    if (module == (PyObject *)NULL) {
+      cerr << "direct.showbase not importable\n";
+      PyErr_Print();
+      Py_Finalize();
+      exit(1);
+    }
+    Py_DECREF(module);
+
+    module = PyImport_ImportModule("direct.showbase.RunAppMF");
+    if (module == (PyObject *)NULL) {
+      cerr << "RunAppMF not importable\n";
+      PyErr_Print();
+      Py_Finalize();
+      exit(1);
+    }
+    Py_DECREF(module);
+  }
+  {
+    // Now that Python is initialized, call the startup function.
+    PyObject *module = PyImport_ImportModule("direct.showbase.RunAppMF");
+    if (module != (PyObject *)NULL) {
+      PyObject *func = PyObject_GetAttrString(module, "runPackedApp");
+      if (func != (PyObject *)NULL) {
+        NSString *script_pathname = [app_directory stringByAppendingString: @"/iphone.mf" ];
+        const char *script_pathname_cstr = [script_pathname cStringUsingEncoding: NSASCIIStringEncoding];
+        PyObject *result = PyObject_CallFunction(func, "([s])", script_pathname_cstr);
+        Py_XDECREF(result);
+        Py_DECREF(func);
+      }
+      Py_DECREF(module);
+    }
+
+    if (PyErr_Occurred()) {
+      PyErr_Print();
+      Py_Finalize();
+      exit(1);
+    }
+  }
+  cerr << "Successfully started.\n";
+  return 0;
+}
+
 int
 main(int argc, char *argv[]) { 
   /*
@@ -249,6 +371,8 @@ main(int argc, char *argv[]) {
 
   /* Call with the name of our application delegate class */ 
   int retVal = UIApplicationMain(argc, argv, nil, @"AppMFAppDelegate"); 
+  //int retVal = quickstart();
+
   [pool release]; 
   return retVal; 
 } 

+ 2 - 2
panda/src/mesadisplay/osMesaGraphicsStateGuardian.cxx

@@ -52,7 +52,7 @@ OSMesaGraphicsStateGuardian::
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: OSMesaGraphicsStateGuardian::get_extension_func
+//     Function: OSMesaGraphicsStateGuardian::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
@@ -62,7 +62,7 @@ OSMesaGraphicsStateGuardian::
 //               not defined.
 ////////////////////////////////////////////////////////////////////
 void *OSMesaGraphicsStateGuardian::
-get_extension_func(const char *prefix, const char *name) {
+do_get_extension_func(const char *prefix, const char *name) {
 #if (OSMESA_MAJOR_VERSION == 4 && OSMESA_MINOR_VERSION >= 1) || OSMESA_MAJOR_VERSION > 4
   // If we've got at least OSMesa version 4.1, then we can use
   // OSMesaGetProcAddress.

+ 1 - 1
panda/src/mesadisplay/osMesaGraphicsStateGuardian.h

@@ -32,7 +32,7 @@ public:
   OSMesaContext _context;
 
 protected:
-  virtual void *get_extension_func(const char *prefix, const char *name);
+  virtual void *do_get_extension_func(const char *prefix, const char *name);
 
 public:
   static TypeHandle get_class_type() {

+ 2 - 2
panda/src/osxdisplay/osxGraphicsStateGuardian.cxx

@@ -29,7 +29,7 @@
 TypeHandle osxGraphicsStateGuardian::_type_handle;
 
 ////////////////////////////////////////////////////////////////////
-//     Function: osxGraphicsStateGuardian::get_extension_func
+//     Function: osxGraphicsStateGuardian::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
@@ -39,7 +39,7 @@ TypeHandle osxGraphicsStateGuardian::_type_handle;
 //               not defined.
 ////////////////////////////////////////////////////////////////////
 void *osxGraphicsStateGuardian::
-get_extension_func(const char *prefix, const char *name) {      
+do_get_extension_func(const char *prefix, const char *name) {      
   string fullname = "_" + string(prefix) + string(name);
   NSSymbol symbol = NULL;
   

+ 1 - 1
panda/src/osxdisplay/osxGraphicsStateGuardian.h

@@ -47,7 +47,7 @@ public:
   void restore_gamma();
         
 protected:
-  virtual void *get_extension_func(const char *prefix, const char *name);
+  virtual void *do_get_extension_func(const char *prefix, const char *name);
   
 public:
   OSStatus build_gl(bool full_screen, bool pbuffer, FrameBufferProperties &fb_props);

+ 2 - 2
panda/src/wgldisplay/wglGraphicsStateGuardian.cxx

@@ -534,7 +534,7 @@ get_extra_extensions() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: wglGraphicsStateGuardian::get_extension_func
+//     Function: wglGraphicsStateGuardian::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
@@ -544,7 +544,7 @@ get_extra_extensions() {
 //               not defined.
 ////////////////////////////////////////////////////////////////////
 void *wglGraphicsStateGuardian::
-get_extension_func(const char *prefix, const char *name) {
+do_get_extension_func(const char *prefix, const char *name) {
   string fullname = string(prefix) + string(name);
   return wglGetProcAddress(fullname.c_str());
 }

+ 1 - 1
panda/src/wgldisplay/wglGraphicsStateGuardian.h

@@ -54,7 +54,7 @@ public:
 
 protected:
   virtual void get_extra_extensions();
-  virtual void *get_extension_func(const char *prefix, const char *name);
+  virtual void *do_get_extension_func(const char *prefix, const char *name);
 
 private:
   void make_context(HDC hdc);