Explorar o código

reverted opengles removal.

Ozkan Sezer %!s(int64=2) %!d(string=hai) anos
pai
achega
34231f5ba0

+ 1 - 0
.gitignore

@@ -118,6 +118,7 @@ test/testgamecontroller
 test/testgeometry
 test/testgesture
 test/testgl2
+test/testgles
 test/testgles2
 test/testhaptic
 test/testhittesting

+ 12 - 1
CMakeLists.txt

@@ -1290,6 +1290,8 @@ if(ANDROID)
     if(SDL_OPENGLES)
       set(SDL_VIDEO_OPENGL_EGL 1)
       set(HAVE_OPENGLES TRUE)
+      set(SDL_VIDEO_OPENGL_ES 1)
+      set(SDL_VIDEO_RENDER_OGL_ES 1)
       set(SDL_VIDEO_OPENGL_ES2 1)
       set(SDL_VIDEO_RENDER_OGL_ES2 1)
 
@@ -2091,7 +2093,11 @@ elseif(APPLE)
     endif()
 
     if(SDL_OPENGLES)
-      if(NOT (IOS OR TVOS))
+      if(IOS OR TVOS)
+        set(SDL_FRAMEWORK_OPENGLES 1)
+        set(SDL_VIDEO_OPENGL_ES 1)
+        set(SDL_VIDEO_RENDER_OGL_ES 1)
+      else()
         set(SDL_VIDEO_OPENGL_EGL 1)
       endif()
       set(SDL_VIDEO_OPENGL_ES2 1)
@@ -2180,6 +2186,9 @@ elseif(APPLE)
       list(APPEND EXTRA_LDFLAGS "-Wl,-weak_framework,Metal")
     endif()
   endif()
+  if(SDL_FRAMEWORK_OPENGLES)
+    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,OpenGLES")
+  endif()
   if(SDL_FRAMEWORK_QUARTZCORE)
     if(IOS OR TVOS)
       list(APPEND EXTRA_LDFLAGS "-Wl,-framework,QuartzCore")
@@ -2402,6 +2411,8 @@ elseif(VITA)
         check_include_file(gl4esinit.h HAVE_GL4ES_H)
         set(SDL_VIDEO_OPENGL_EGL 1)
         set(HAVE_OPENGLES TRUE)
+        set(SDL_VIDEO_OPENGL_ES 1)
+        set(SDL_VIDEO_RENDER_OGL_ES 1)
         set(SDL_VIDEO_OPENGL_ES2 1)
         set(SDL_VIDEO_RENDER_OGL_ES2 1)
 

+ 1 - 0
Makefile.in

@@ -100,6 +100,7 @@ HDRS = \
 	SDL_name.h \
 	SDL_opengl.h \
 	SDL_opengl_glext.h \
+	SDL_opengles.h \
 	SDL_opengles2_gl2ext.h \
 	SDL_opengles2_gl2.h \
 	SDL_opengles2_gl2platform.h \

+ 1 - 0
VisualC-GDK/SDL/SDL.vcxproj

@@ -329,6 +329,7 @@
     <ClInclude Include="..\..\include\SDL_name.h" />
     <ClInclude Include="..\..\include\SDL_opengl.h" />
     <ClInclude Include="..\..\include\SDL_opengl_glext.h" />
+    <ClInclude Include="..\..\include\SDL_opengles.h" />
     <ClInclude Include="..\..\include\SDL_opengles2.h" />
     <ClInclude Include="..\..\include\SDL_opengles2_gl2.h" />
     <ClInclude Include="..\..\include\SDL_opengles2_gl2ext.h" />

+ 3 - 0
VisualC-GDK/SDL/SDL.vcxproj.filters

@@ -282,6 +282,9 @@
     <ClInclude Include="..\..\include\SDL_opengl_glext.h">
       <Filter>API Headers</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\SDL_opengles.h">
+      <Filter>API Headers</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\SDL_opengles2.h">
       <Filter>API Headers</Filter>
     </ClInclude>

+ 1 - 0
VisualC/SDL/SDL.vcxproj

@@ -253,6 +253,7 @@
     <ClInclude Include="..\..\include\SDL_name.h" />
     <ClInclude Include="..\..\include\SDL_opengl.h" />
     <ClInclude Include="..\..\include\SDL_opengl_glext.h" />
+    <ClInclude Include="..\..\include\SDL_opengles.h" />
     <ClInclude Include="..\..\include\SDL_opengles2.h" />
     <ClInclude Include="..\..\include\SDL_opengles2_gl2.h" />
     <ClInclude Include="..\..\include\SDL_opengles2_gl2ext.h" />

+ 3 - 0
VisualC/SDL/SDL.vcxproj.filters

@@ -282,6 +282,9 @@
     <ClInclude Include="..\..\include\SDL_opengl_glext.h">
       <Filter>API Headers</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\SDL_opengles.h">
+      <Filter>API Headers</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\SDL_opengles2.h">
       <Filter>API Headers</Filter>
     </ClInclude>

+ 9 - 0
cmake/sdlchecks.cmake

@@ -700,6 +700,15 @@ endmacro()
 # - nada
 macro(CheckOpenGLES)
   if(SDL_OPENGLES)
+    check_c_source_compiles("
+        #include <GLES/gl.h>
+        #include <GLES/glext.h>
+        int main (int argc, char** argv) { return 0; }" HAVE_OPENGLES_V1)
+    if(HAVE_OPENGLES_V1)
+        set(HAVE_OPENGLES TRUE)
+        set(SDL_VIDEO_OPENGL_ES 1)
+        set(SDL_VIDEO_RENDER_OGL_ES 1)
+    endif()
     check_c_source_compiles("
         #include <GLES2/gl2.h>
         #include <GLES2/gl2ext.h>

+ 54 - 0
configure

@@ -911,6 +911,7 @@ enable_video_dummy
 enable_video_offscreen
 enable_video_opengl
 enable_video_opengles
+enable_video_opengles1
 enable_video_opengles2
 enable_video_vulkan
 enable_libudev
@@ -1705,6 +1706,8 @@ Optional Features:
                           use offscreen video driver [default=yes]
   --enable-video-opengl   include OpenGL support [default=yes]
   --enable-video-opengles include OpenGL ES support [default=yes]
+  --enable-video-opengles1
+                          include OpenGL ES 1.1 support [default=yes]
   --enable-video-opengles2
                           include OpenGL ES 2.0 support [default=yes]
   --enable-video-vulkan   include Vulkan support [default=yes]
@@ -24665,6 +24668,14 @@ else $as_nop
   enable_video_opengles=yes
 fi
 
+# Check whether --enable-video-opengles1 was given.
+if test ${enable_video_opengles1+y}
+then :
+  enableval=$enable_video_opengles1;
+else $as_nop
+  enable_video_opengles1=yes
+fi
+
 # Check whether --enable-video-opengles2 was given.
 if test ${enable_video_opengles2+y}
 then :
@@ -24755,6 +24766,42 @@ printf "%s\n" "#define SDL_VIDEO_RENDER_OGL 1" >>confdefs.h
 CheckOpenGLES()
 {
     if test x$enable_video = xyes -a x$enable_video_opengles = xyes; then
+        if test x$enable_video_opengles1 = xyes; then
+            { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OpenGL ES v1 headers" >&5
+printf %s "checking for OpenGL ES v1 headers... " >&6; }
+            video_opengles_v1=no
+            cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+             #include <GLES/gl.h>
+             #include <GLES/glext.h>
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+  video_opengles_v1=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+            { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $video_opengles_v1" >&5
+printf "%s\n" "$video_opengles_v1" >&6; }
+            if test x$video_opengles_v1 = xyes; then
+
+printf "%s\n" "#define SDL_VIDEO_OPENGL_ES 1" >>confdefs.h
+
+
+printf "%s\n" "#define SDL_VIDEO_RENDER_OGL_ES 1" >>confdefs.h
+
+                SUMMARY_video="${SUMMARY_video} opengl_es1"
+            fi
+        fi
+
         if test x$enable_video_opengles2 = xyes; then
             { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OpenGL ES v2 headers" >&5
 printf %s "checking for OpenGL ES v2 headers... " >&6; }
@@ -27930,6 +27977,12 @@ printf "%s\n" "#define SDL_VIDEO_DRIVER_UIKIT 1" >>confdefs.h
 printf "%s\n" "#define SDL_VIDEO_OPENGL_ES2 1" >>confdefs.h
 
 
+printf "%s\n" "#define SDL_VIDEO_OPENGL_ES 1" >>confdefs.h
+
+
+printf "%s\n" "#define SDL_VIDEO_RENDER_OGL_ES 1" >>confdefs.h
+
+
 printf "%s\n" "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h
 
         SOURCES="$SOURCES $srcdir/src/video/uikit/*.m"
@@ -27947,6 +28000,7 @@ printf "%s\n" "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreMotion"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Foundation"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,GameController"
+        EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,OpenGLES"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,UIKit"
 

+ 21 - 0
configure.ac

@@ -2211,6 +2211,9 @@ dnl Check to see if OpenGL ES support is desired
 AC_ARG_ENABLE(video-opengles,
 [AS_HELP_STRING([--enable-video-opengles], [include OpenGL ES support [default=yes]])],
               , enable_video_opengles=yes)
+AC_ARG_ENABLE(video-opengles1,
+[AS_HELP_STRING([--enable-video-opengles1], [include OpenGL ES 1.1 support [default=yes]])],
+              , enable_video_opengles1=yes)
 AC_ARG_ENABLE(video-opengles2,
 [AS_HELP_STRING([--enable-video-opengles2], [include OpenGL ES 2.0 support [default=yes]])],
               , enable_video_opengles2=yes)
@@ -2259,6 +2262,21 @@ dnl Find OpenGL ES
 CheckOpenGLES()
 {
     if test x$enable_video = xyes -a x$enable_video_opengles = xyes; then
+        if test x$enable_video_opengles1 = xyes; then
+            AC_MSG_CHECKING(for OpenGL ES v1 headers)
+            video_opengles_v1=no
+            AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+             #include <GLES/gl.h>
+             #include <GLES/glext.h>
+            ]],[])], [video_opengles_v1=yes],[])
+            AC_MSG_RESULT($video_opengles_v1)
+            if test x$video_opengles_v1 = xyes; then
+                AC_DEFINE(SDL_VIDEO_OPENGL_ES, 1, [ ])
+                AC_DEFINE(SDL_VIDEO_RENDER_OGL_ES, 1, [ ])
+                SUMMARY_video="${SUMMARY_video} opengl_es1"
+            fi
+        fi
+
         if test x$enable_video_opengles2 = xyes; then
             AC_MSG_CHECKING(for OpenGL ES v2 headers)
             video_opengles_v2=no
@@ -3966,6 +3984,8 @@ dnl BeOS support removed after SDL 2.0.1. Haiku still works.  --ryan.
         # The iOS platform requires special setup.
         AC_DEFINE(SDL_VIDEO_DRIVER_UIKIT, 1, [ ])
         AC_DEFINE(SDL_VIDEO_OPENGL_ES2, 1, [ ])
+        AC_DEFINE(SDL_VIDEO_OPENGL_ES, 1, [ ])
+        AC_DEFINE(SDL_VIDEO_RENDER_OGL_ES, 1, [ ])
         AC_DEFINE(SDL_VIDEO_RENDER_OGL_ES2, 1, [ ])
         SOURCES="$SOURCES $srcdir/src/video/uikit/*.m"
         SUMMARY_video="${SUMMARY_video} uikit"
@@ -3982,6 +4002,7 @@ dnl BeOS support removed after SDL 2.0.1. Haiku still works.  --ryan.
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,CoreMotion"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Foundation"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,GameController"
+        EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,OpenGLES"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,UIKit"
 

+ 1 - 0
docs/doxyfile

@@ -637,6 +637,7 @@ EXCLUDE                = ../include/SDL_opengles2_gl2ext.h \
                          ../include/SDL_opengl_glext.h \
                          ../include/SDL_opengles2_gl2.h \
                          ../include/SDL_opengles2.h \
+                         ../include/SDL_opengles.h \
                          ../include/SDL_opengl.h \
                          ../include/SDL_egl.h \
                          ./release_checklist.md \

+ 2 - 0
include/SDL_config.h.cmake

@@ -434,6 +434,7 @@
 #cmakedefine SDL_VIDEO_RENDER_D3D11 @SDL_VIDEO_RENDER_D3D11@
 #cmakedefine SDL_VIDEO_RENDER_D3D12 @SDL_VIDEO_RENDER_D3D12@
 #cmakedefine SDL_VIDEO_RENDER_OGL @SDL_VIDEO_RENDER_OGL@
+#cmakedefine SDL_VIDEO_RENDER_OGL_ES @SDL_VIDEO_RENDER_OGL_ES@
 #cmakedefine SDL_VIDEO_RENDER_OGL_ES2 @SDL_VIDEO_RENDER_OGL_ES2@
 #cmakedefine SDL_VIDEO_RENDER_METAL @SDL_VIDEO_RENDER_METAL@
 #cmakedefine SDL_VIDEO_RENDER_VITA_GXM @SDL_VIDEO_RENDER_VITA_GXM@
@@ -442,6 +443,7 @@
 
 /* Enable OpenGL support */
 #cmakedefine SDL_VIDEO_OPENGL @SDL_VIDEO_OPENGL@
+#cmakedefine SDL_VIDEO_OPENGL_ES @SDL_VIDEO_OPENGL_ES@
 #cmakedefine SDL_VIDEO_OPENGL_ES2 @SDL_VIDEO_OPENGL_ES2@
 #cmakedefine SDL_VIDEO_OPENGL_BGL @SDL_VIDEO_OPENGL_BGL@
 #cmakedefine SDL_VIDEO_OPENGL_CGL @SDL_VIDEO_OPENGL_CGL@

+ 2 - 0
include/SDL_config.h.in

@@ -395,11 +395,13 @@
 #undef SDL_VIDEO_RENDER_D3D11
 #undef SDL_VIDEO_RENDER_D3D12
 #undef SDL_VIDEO_RENDER_OGL
+#undef SDL_VIDEO_RENDER_OGL_ES
 #undef SDL_VIDEO_RENDER_OGL_ES2
 #undef SDL_VIDEO_RENDER_METAL
 
 /* Enable OpenGL support */
 #undef SDL_VIDEO_OPENGL
+#undef SDL_VIDEO_OPENGL_ES
 #undef SDL_VIDEO_OPENGL_ES2
 #undef SDL_VIDEO_OPENGL_BGL
 #undef SDL_VIDEO_OPENGL_CGL

+ 2 - 0
include/SDL_config_android.h

@@ -171,8 +171,10 @@
 #define SDL_VIDEO_DRIVER_ANDROID 1
 
 /* Enable OpenGL ES */
+#define SDL_VIDEO_OPENGL_ES 1
 #define SDL_VIDEO_OPENGL_ES2 1
 #define SDL_VIDEO_OPENGL_EGL 1
+#define SDL_VIDEO_RENDER_OGL_ES 1
 #define SDL_VIDEO_RENDER_OGL_ES2    1
 
 /* Enable Vulkan support */

+ 1 - 0
include/SDL_config_emscripten.h

@@ -199,6 +199,7 @@
 
 /* Enable OpenGL support */
 /* #undef SDL_VIDEO_OPENGL */
+/* #undef SDL_VIDEO_OPENGL_ES */
 #define SDL_VIDEO_OPENGL_ES2 1
 /* #undef SDL_VIDEO_OPENGL_BGL */
 /* #undef SDL_VIDEO_OPENGL_CGL */

+ 2 - 0
include/SDL_config_iphoneos.h

@@ -176,6 +176,8 @@
 /* Enable OpenGL ES */
 #if !TARGET_OS_MACCATALYST
 #define SDL_VIDEO_OPENGL_ES2 1
+#define SDL_VIDEO_OPENGL_ES 1
+#define SDL_VIDEO_RENDER_OGL_ES 1
 #define SDL_VIDEO_RENDER_OGL_ES2    1
 #endif
 

+ 39 - 0
include/SDL_opengles.h

@@ -0,0 +1,39 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/**
+ *  \file SDL_opengles.h
+ *
+ *  This is a simple file to encapsulate the OpenGL ES 1.X API headers.
+ */
+#include "SDL_config.h"
+
+#ifdef __IPHONEOS__
+#include <OpenGLES/ES1/gl.h>
+#include <OpenGLES/ES1/glext.h>
+#else
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif

+ 3 - 0
src/render/SDL_render.c

@@ -109,6 +109,9 @@ static const SDL_RenderDriver *render_drivers[] = {
 #if SDL_VIDEO_RENDER_OGL_ES2
     &GLES2_RenderDriver,
 #endif
+#if SDL_VIDEO_RENDER_OGL_ES
+    &GLES_RenderDriver,
+#endif
 #if SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED
     &PS2_RenderDriver,
 #endif

+ 1 - 0
src/render/SDL_sysrender.h

@@ -299,6 +299,7 @@ extern SDL_RenderDriver D3D11_RenderDriver;
 extern SDL_RenderDriver D3D12_RenderDriver;
 extern SDL_RenderDriver GL_RenderDriver;
 extern SDL_RenderDriver GLES2_RenderDriver;
+extern SDL_RenderDriver GLES_RenderDriver;
 extern SDL_RenderDriver METAL_RenderDriver;
 extern SDL_RenderDriver PS2_RenderDriver;
 extern SDL_RenderDriver PSP_RenderDriver;

+ 62 - 0
src/render/opengles/SDL_glesfuncs.h

@@ -0,0 +1,62 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+SDL_PROC(void, glBindTexture, (GLenum, GLuint))
+SDL_PROC(void, glBlendFunc, (GLenum, GLenum))
+SDL_PROC_OES(void, glBlendEquationOES, (GLenum))
+SDL_PROC_OES(void, glBlendEquationSeparateOES, (GLenum, GLenum))
+SDL_PROC_OES(void, glBlendFuncSeparateOES, (GLenum, GLenum, GLenum, GLenum))
+SDL_PROC(void, glClear, (GLbitfield))
+SDL_PROC(void, glClearColor, (GLclampf, GLclampf, GLclampf, GLclampf))
+SDL_PROC(void, glColor4f, (GLfloat, GLfloat, GLfloat, GLfloat))
+SDL_PROC(void, glColorPointer, (GLint, GLenum, GLsizei, const GLvoid *))
+SDL_PROC(void, glDeleteTextures, (GLsizei, const GLuint *))
+SDL_PROC(void, glDisable, (GLenum))
+SDL_PROC(void, glDisableClientState, (GLenum array))
+SDL_PROC(void, glDrawArrays, (GLenum, GLint, GLsizei))
+SDL_PROC_OES(void, glDrawTexfOES, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat))
+SDL_PROC(void, glEnable, (GLenum))
+SDL_PROC(void, glEnableClientState, (GLenum))
+SDL_PROC(void, glFinish, (void))
+SDL_PROC_OES(void, glGenFramebuffersOES, (GLsizei, GLuint *))
+SDL_PROC(void, glGenTextures, (GLsizei, GLuint *))
+SDL_PROC(GLenum, glGetError, (void))
+SDL_PROC(void, glGetIntegerv, (GLenum, GLint *))
+SDL_PROC(void, glLoadIdentity, (void))
+SDL_PROC(void, glMatrixMode, (GLenum))
+SDL_PROC(void, glOrthof, (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat))
+SDL_PROC(void, glPixelStorei, (GLenum, GLint))
+SDL_PROC(void, glReadPixels, (GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*))
+SDL_PROC(void, glScissor, (GLint, GLint, GLsizei, GLsizei))
+SDL_PROC(void, glTexCoordPointer, (GLint, GLenum, GLsizei, const GLvoid *))
+SDL_PROC(void, glTexEnvf, (GLenum, GLenum, GLfloat))
+SDL_PROC(void, glTexImage2D, (GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *))
+SDL_PROC(void, glTexParameteri, (GLenum, GLenum, GLint))
+SDL_PROC(void, glTexParameteriv, (GLenum, GLenum, const GLint *))
+SDL_PROC(void, glTexSubImage2D, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *))
+SDL_PROC(void, glVertexPointer, (GLint, GLenum, GLsizei, const GLvoid *))
+SDL_PROC(void, glViewport, (GLint, GLint, GLsizei, GLsizei))
+SDL_PROC_OES(void, glBindFramebufferOES, (GLenum, GLuint))
+SDL_PROC_OES(void, glFramebufferTexture2DOES, (GLenum, GLenum, GLenum, GLuint, GLint))
+SDL_PROC_OES(GLenum, glCheckFramebufferStatusOES, (GLenum))
+SDL_PROC_OES(void, glDeleteFramebuffersOES, (GLsizei, const GLuint*))
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 1218 - 0
src/render/opengles/SDL_render_gles.c

@@ -0,0 +1,1218 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED
+
+#include "SDL_hints.h"
+#include "../../video/SDL_sysvideo.h" /* For SDL_GL_SwapWindowWithResult */
+#include "SDL_opengles.h"
+#include "../SDL_sysrender.h"
+#include "../../SDL_utils_c.h"
+
+/* To prevent unnecessary window recreation,
+ * these should match the defaults selected in SDL_GL_ResetAttributes
+ */
+
+#define RENDERER_CONTEXT_MAJOR 1
+#define RENDERER_CONTEXT_MINOR 1
+
+/* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */
+
+/* Used to re-create the window with OpenGL ES capability */
+extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
+
+static const float inv255f = 1.0f / 255.0f;
+
+typedef struct GLES_FBOList GLES_FBOList;
+
+struct GLES_FBOList
+{
+   Uint32 w, h;
+   GLuint FBO;
+   GLES_FBOList *next;
+};
+
+typedef struct
+{
+    SDL_Rect viewport;
+    SDL_bool viewport_dirty;
+    SDL_Texture *texture;
+    SDL_Texture *target;
+    int drawablew;
+    int drawableh;
+    SDL_BlendMode blend;
+    SDL_bool cliprect_enabled_dirty;
+    SDL_bool cliprect_enabled;
+    SDL_bool cliprect_dirty;
+    SDL_Rect cliprect;
+    SDL_bool texturing;
+    Uint32 color;
+    Uint32 clear_color;
+} GLES_DrawStateCache;
+
+typedef struct
+{
+    SDL_GLContext context;
+
+#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
+#define SDL_PROC_OES SDL_PROC
+#include "SDL_glesfuncs.h"
+#undef SDL_PROC
+#undef SDL_PROC_OES
+    SDL_bool GL_OES_framebuffer_object_supported;
+    GLES_FBOList *framebuffers;
+    GLuint window_framebuffer;
+
+    SDL_bool GL_OES_blend_func_separate_supported;
+    SDL_bool GL_OES_blend_equation_separate_supported;
+    SDL_bool GL_OES_blend_subtract_supported;
+
+    GLES_DrawStateCache drawstate;
+} GLES_RenderData;
+
+typedef struct
+{
+    GLuint texture;
+    GLenum type;
+    GLfloat texw;
+    GLfloat texh;
+    GLenum format;
+    GLenum formattype;
+    void *pixels;
+    int pitch;
+    GLES_FBOList *fbo;
+} GLES_TextureData;
+
+static int
+GLES_SetError(const char *prefix, GLenum result)
+{
+    const char *error;
+
+    switch (result) {
+    case GL_NO_ERROR:
+        error = "GL_NO_ERROR";
+        break;
+    case GL_INVALID_ENUM:
+        error = "GL_INVALID_ENUM";
+        break;
+    case GL_INVALID_VALUE:
+        error = "GL_INVALID_VALUE";
+        break;
+    case GL_INVALID_OPERATION:
+        error = "GL_INVALID_OPERATION";
+        break;
+    case GL_STACK_OVERFLOW:
+        error = "GL_STACK_OVERFLOW";
+        break;
+    case GL_STACK_UNDERFLOW:
+        error = "GL_STACK_UNDERFLOW";
+        break;
+    case GL_OUT_OF_MEMORY:
+        error = "GL_OUT_OF_MEMORY";
+        break;
+    default:
+        error = "UNKNOWN";
+        break;
+    }
+    return SDL_SetError("%s: %s", prefix, error);
+}
+
+static int GLES_LoadFunctions(GLES_RenderData * data)
+{
+#if SDL_VIDEO_DRIVER_UIKIT
+#define __SDL_NOGETPROCADDR__
+#elif SDL_VIDEO_DRIVER_ANDROID
+#define __SDL_NOGETPROCADDR__
+#endif
+
+#ifdef __SDL_NOGETPROCADDR__
+#define SDL_PROC(ret,func,params) data->func=func;
+#define SDL_PROC_OES(ret,func,params) data->func=func;
+#else
+#define SDL_PROC(ret,func,params) \
+    do { \
+        data->func = SDL_GL_GetProcAddress(#func); \
+        if ( ! data->func ) { \
+            return SDL_SetError("Couldn't load GLES function %s: %s", #func, SDL_GetError()); \
+        } \
+    } while ( 0 );
+#define SDL_PROC_OES(ret,func,params) \
+    do { \
+        data->func = SDL_GL_GetProcAddress(#func); \
+    } while ( 0 );
+#endif /* __SDL_NOGETPROCADDR__ */
+
+#include "SDL_glesfuncs.h"
+#undef SDL_PROC
+#undef SDL_PROC_OES
+    return 0;
+}
+
+static GLES_FBOList *
+GLES_GetFBO(GLES_RenderData *data, Uint32 w, Uint32 h)
+{
+   GLES_FBOList *result = data->framebuffers;
+   while ((result) && ((result->w != w) || (result->h != h)) ) {
+       result = result->next;
+   }
+   if (result == NULL) {
+       result = SDL_malloc(sizeof(GLES_FBOList));
+       result->w = w;
+       result->h = h;
+       data->glGenFramebuffersOES(1, &result->FBO);
+       result->next = data->framebuffers;
+       data->framebuffers = result;
+   }
+   return result;
+}
+
+
+static int
+GLES_ActivateRenderer(SDL_Renderer * renderer)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+
+    if (SDL_GL_GetCurrentContext() != data->context) {
+        if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static void
+GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+
+    if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
+        /* According to Apple documentation, we need to finish drawing NOW! */
+        data->glFinish();
+    }
+}
+
+static int
+GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
+{
+    SDL_GL_GetDrawableSize(renderer->window, w, h);
+    return 0;
+}
+
+static GLenum GetBlendFunc(SDL_BlendFactor factor)
+{
+    switch (factor) {
+    case SDL_BLENDFACTOR_ZERO:
+        return GL_ZERO;
+    case SDL_BLENDFACTOR_ONE:
+        return GL_ONE;
+    case SDL_BLENDFACTOR_SRC_COLOR:
+        return GL_SRC_COLOR;
+    case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
+        return GL_ONE_MINUS_SRC_COLOR;
+    case SDL_BLENDFACTOR_SRC_ALPHA:
+        return GL_SRC_ALPHA;
+    case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
+        return GL_ONE_MINUS_SRC_ALPHA;
+    case SDL_BLENDFACTOR_DST_COLOR:
+        return GL_DST_COLOR;
+    case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
+        return GL_ONE_MINUS_DST_COLOR;
+    case SDL_BLENDFACTOR_DST_ALPHA:
+        return GL_DST_ALPHA;
+    case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
+        return GL_ONE_MINUS_DST_ALPHA;
+    default:
+        return GL_INVALID_ENUM;
+    }
+}
+
+static GLenum GetBlendEquation(SDL_BlendOperation operation)
+{
+    switch (operation) {
+    case SDL_BLENDOPERATION_ADD:
+        return GL_FUNC_ADD_OES;
+    case SDL_BLENDOPERATION_SUBTRACT:
+        return GL_FUNC_SUBTRACT_OES;
+    case SDL_BLENDOPERATION_REV_SUBTRACT:
+        return GL_FUNC_REVERSE_SUBTRACT_OES;
+    default:
+        return GL_INVALID_ENUM;
+    }
+}
+
+static SDL_bool
+GLES_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+    SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
+    SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
+    SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
+    SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
+    SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
+    SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
+
+    if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM ||
+        GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM ||
+        GetBlendEquation(colorOperation) == GL_INVALID_ENUM ||
+        GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM ||
+        GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM ||
+        GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) {
+        return SDL_FALSE;
+    }
+    if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->GL_OES_blend_func_separate_supported) {
+        return SDL_FALSE;
+    }
+    if (colorOperation != alphaOperation && !data->GL_OES_blend_equation_separate_supported) {
+        return SDL_FALSE;
+    }
+    if (colorOperation != SDL_BLENDOPERATION_ADD && !data->GL_OES_blend_subtract_supported) {
+        return SDL_FALSE;
+    }
+    return SDL_TRUE;
+}
+
+static int
+GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
+    GLES_TextureData *data;
+    GLint internalFormat;
+    GLenum format, type;
+    int texture_w, texture_h;
+    GLenum scaleMode;
+    GLenum result;
+
+    GLES_ActivateRenderer(renderer);
+
+    switch (texture->format) {
+    case SDL_PIXELFORMAT_ABGR8888:
+        internalFormat = GL_RGBA;
+        format = GL_RGBA;
+        type = GL_UNSIGNED_BYTE;
+        break;
+    default:
+        return SDL_SetError("Texture format not supported");
+    }
+
+    data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data));
+    if (!data) {
+        return SDL_OutOfMemory();
+    }
+
+    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
+        data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
+        data->pixels = SDL_calloc(1, texture->h * data->pitch);
+        if (!data->pixels) {
+            SDL_free(data);
+            return SDL_OutOfMemory();
+        }
+    }
+
+
+    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
+        if (!renderdata->GL_OES_framebuffer_object_supported) {
+            SDL_free(data);
+            return SDL_SetError("GL_OES_framebuffer_object not supported");
+        }
+        data->fbo = GLES_GetFBO(renderer->driverdata, texture->w, texture->h);
+    } else {
+        data->fbo = NULL;
+    }
+
+
+    renderdata->glGetError();
+    renderdata->glEnable(GL_TEXTURE_2D);
+    renderdata->glGenTextures(1, &data->texture);
+    result = renderdata->glGetError();
+    if (result != GL_NO_ERROR) {
+        if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
+            SDL_free(data->pixels);
+        }
+        SDL_free(data);
+        return GLES_SetError("glGenTextures()", result);
+    }
+
+    data->type = GL_TEXTURE_2D;
+    /* no NPOV textures allowed in OpenGL ES (yet) */
+    texture_w = SDL_powerof2(texture->w);
+    texture_h = SDL_powerof2(texture->h);
+    data->texw = (GLfloat) texture->w / texture_w;
+    data->texh = (GLfloat) texture->h / texture_h;
+
+    data->format = format;
+    data->formattype = type;
+    scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
+    renderdata->glBindTexture(data->type, data->texture);
+    renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
+    renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
+    renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
+                             texture_h, 0, format, type, NULL);
+    renderdata->glDisable(GL_TEXTURE_2D);
+    renderdata->drawstate.texture = texture;
+    renderdata->drawstate.texturing = SDL_FALSE;
+
+    result = renderdata->glGetError();
+    if (result != GL_NO_ERROR) {
+        if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
+            SDL_free(data->pixels);
+        }
+        SDL_free(data);
+        return GLES_SetError("glTexImage2D()", result);
+    }
+
+    texture->driverdata = data;
+    return 0;
+}
+
+static int
+GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
+                   const SDL_Rect * rect, const void *pixels, int pitch)
+{
+    GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
+    GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
+    Uint8 *blob = NULL;
+    Uint8 *src;
+    int srcPitch;
+    int y;
+
+    GLES_ActivateRenderer(renderer);
+
+    /* Bail out if we're supposed to update an empty rectangle */
+    if (rect->w <= 0 || rect->h <= 0) {
+        return 0;
+    }
+
+    /* Reformat the texture data into a tightly packed array */
+    srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format);
+    src = (Uint8 *)pixels;
+    if (pitch != srcPitch) {
+        blob = (Uint8 *)SDL_malloc(srcPitch * rect->h);
+        if (!blob) {
+            return SDL_OutOfMemory();
+        }
+        src = blob;
+        for (y = 0; y < rect->h; ++y) {
+            SDL_memcpy(src, pixels, srcPitch);
+            src += srcPitch;
+            pixels = (Uint8 *)pixels + pitch;
+        }
+        src = blob;
+    }
+
+    /* Create a texture subimage with the supplied data */
+    renderdata->glGetError();
+    renderdata->glEnable(data->type);
+    renderdata->glBindTexture(data->type, data->texture);
+    renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    renderdata->glTexSubImage2D(data->type,
+                    0,
+                    rect->x,
+                    rect->y,
+                    rect->w,
+                    rect->h,
+                    data->format,
+                    data->formattype,
+                    src);
+    renderdata->glDisable(data->type);
+    SDL_free(blob);
+
+    renderdata->drawstate.texture = texture;
+    renderdata->drawstate.texturing = SDL_FALSE;
+
+    if (renderdata->glGetError() != GL_NO_ERROR) {
+        return SDL_SetError("Failed to update texture");
+    }
+    return 0;
+}
+
+static int
+GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
+                 const SDL_Rect * rect, void **pixels, int *pitch)
+{
+    GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
+
+    *pixels =
+        (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
+                  rect->x * SDL_BYTESPERPIXEL(texture->format));
+    *pitch = data->pitch;
+    return 0;
+}
+
+static void
+GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
+    SDL_Rect rect;
+
+    /* We do whole texture updates, at least for now */
+    rect.x = 0;
+    rect.y = 0;
+    rect.w = texture->w;
+    rect.h = texture->h;
+    GLES_UpdateTexture(renderer, texture, &rect, data->pixels, data->pitch);
+}
+
+static void
+GLES_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
+{
+    GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
+    GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
+    GLenum glScaleMode = (scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
+
+    renderdata->glBindTexture(data->type, data->texture);
+    renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, glScaleMode);
+    renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, glScaleMode);
+}
+
+static int
+GLES_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+    GLES_TextureData *texturedata = NULL;
+    GLenum status;
+
+    if (!data->GL_OES_framebuffer_object_supported) {
+        return SDL_SetError("Can't enable render target support in this renderer");
+    }
+
+    data->drawstate.viewport_dirty = SDL_TRUE;
+
+    if (texture == NULL) {
+        data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, data->window_framebuffer);
+        return 0;
+    }
+
+    texturedata = (GLES_TextureData *) texture->driverdata;
+    data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO);
+    /* TODO: check if texture pixel format allows this operation */
+    data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0);
+    /* Check FBO status */
+    status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
+    if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
+        return SDL_SetError("glFramebufferTexture2DOES() failed");
+    }
+    return 0;
+}
+
+
+static int
+GLES_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
+{
+    return 0;  /* nothing to do in this backend. */
+}
+
+static int
+GLES_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
+{
+    GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
+    int i;
+
+    if (!verts) {
+        return -1;
+    }
+
+    cmd->data.draw.count = count;
+    for (i = 0; i < count; i++) {
+        *(verts++) = 0.5f + points[i].x;
+        *(verts++) = 0.5f + points[i].y;
+    }
+
+    return 0;
+}
+
+static int
+GLES_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
+{
+    int i;
+    GLfloat prevx, prevy;
+    const size_t vertlen = (sizeof (GLfloat) * 2) * count;
+    GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
+
+    if (!verts) {
+        return -1;
+    }
+    cmd->data.draw.count = count;
+
+    /* 0.5f offset to hit the center of the pixel. */
+    prevx = 0.5f + points->x;
+    prevy = 0.5f + points->y;
+    *(verts++) = prevx;
+    *(verts++) = prevy;
+
+    /* bump the end of each line segment out a quarter of a pixel, to provoke
+       the diamond-exit rule. Without this, you won't just drop the last
+       pixel of the last line segment, but you might also drop pixels at the
+       edge of any given line segment along the way too. */
+    for (i = 1; i < count; i++) {
+        const GLfloat xstart = prevx;
+        const GLfloat ystart = prevy;
+        const GLfloat xend = points[i].x + 0.5f;  /* 0.5f to hit pixel center. */
+        const GLfloat yend = points[i].y + 0.5f;
+        /* bump a little in the direction we are moving in. */
+        const GLfloat deltax = xend - xstart;
+        const GLfloat deltay = yend - ystart;
+        const GLfloat angle = SDL_atan2f(deltay, deltax);
+        prevx = xend + (SDL_cosf(angle) * 0.25f);
+        prevy = yend + (SDL_sinf(angle) * 0.25f);
+        *(verts++) = prevx;
+        *(verts++) = prevy;
+    }
+
+    return 0;
+}
+
+static int
+GLES_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
+        const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
+        int num_vertices, const void *indices, int num_indices, int size_indices,
+        float scale_x, float scale_y)
+{
+    GLES_TextureData *texturedata = NULL;
+    int i;
+    int count = indices ? num_indices : num_vertices;
+    GLfloat *verts;
+    int sz = 2 + 4 + (texture ? 2 : 0);
+
+    verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * sz * sizeof (GLfloat), 0, &cmd->data.draw.first);
+    if (!verts) {
+        return -1;
+    }
+
+    if (texture) {
+        texturedata = (GLES_TextureData *) texture->driverdata;
+    }
+
+    cmd->data.draw.count = count;
+    size_indices = indices ? size_indices : 0;
+
+    for (i = 0; i < count; i++) {
+        int j;
+        float *xy_;
+        SDL_Color col_;
+        if (size_indices == 4) {
+            j = ((const Uint32 *)indices)[i];
+        } else if (size_indices == 2) {
+            j = ((const Uint16 *)indices)[i];
+        } else if (size_indices == 1) {
+            j = ((const Uint8 *)indices)[i];
+        } else {
+            j = i;
+        }
+
+        xy_ = (float *)((char*)xy + j * xy_stride);
+        col_ = *(SDL_Color *)((char*)color + j * color_stride);
+
+        *(verts++) = xy_[0] * scale_x;
+        *(verts++) = xy_[1] * scale_y;
+
+        *(verts++) = col_.r * inv255f;
+        *(verts++) = col_.g * inv255f;
+        *(verts++) = col_.b * inv255f;
+        *(verts++) = col_.a * inv255f;
+
+        if (texture) {
+            float *uv_ = (float *)((char*)uv + j * uv_stride);
+            *(verts++) = uv_[0] * texturedata->texw;
+            *(verts++) = uv_[1] * texturedata->texh;
+        }
+    }
+    return 0;
+}
+
+static void
+SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd)
+{
+    const SDL_BlendMode blend = cmd->data.draw.blend;
+    const Uint8 r = cmd->data.draw.r;
+    const Uint8 g = cmd->data.draw.g;
+    const Uint8 b = cmd->data.draw.b;
+    const Uint8 a = cmd->data.draw.a;
+    const Uint32 color = (((Uint32)a << 24) | (r << 16) | (g << 8) | b);
+
+    if (color != data->drawstate.color) {
+        const GLfloat fr = ((GLfloat) r) * inv255f;
+        const GLfloat fg = ((GLfloat) g) * inv255f;
+        const GLfloat fb = ((GLfloat) b) * inv255f;
+        const GLfloat fa = ((GLfloat) a) * inv255f;
+        data->glColor4f(fr, fg, fb, fa);
+        data->drawstate.color = color;
+    }
+
+    if (data->drawstate.viewport_dirty) {
+        const SDL_Rect *viewport = &data->drawstate.viewport;
+        const SDL_bool istarget = (data->drawstate.target != NULL);
+        data->glMatrixMode(GL_PROJECTION);
+        data->glLoadIdentity();
+        data->glViewport(viewport->x,
+                         istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
+                         viewport->w, viewport->h);
+        if (viewport->w && viewport->h) {
+            data->glOrthof((GLfloat) 0, (GLfloat) viewport->w,
+                           (GLfloat) (istarget ? 0 : viewport->h),
+                           (GLfloat) (istarget ? viewport->h : 0),
+                           0.0, 1.0);
+        }
+        data->glMatrixMode(GL_MODELVIEW);
+        data->drawstate.viewport_dirty = SDL_FALSE;
+    }
+
+    if (data->drawstate.cliprect_enabled_dirty) {
+        if (data->drawstate.cliprect_enabled) {
+            data->glEnable(GL_SCISSOR_TEST);
+        } else {
+            data->glDisable(GL_SCISSOR_TEST);
+        }
+        data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
+    }
+
+    if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
+        const SDL_Rect *viewport = &data->drawstate.viewport;
+        const SDL_Rect *rect = &data->drawstate.cliprect;
+        const SDL_bool istarget = (data->drawstate.target != NULL);
+        data->glScissor(viewport->x + rect->x,
+                        istarget ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
+                        rect->w, rect->h);
+        data->drawstate.cliprect_dirty = SDL_FALSE;
+    }
+
+    if (blend != data->drawstate.blend) {
+        if (blend == SDL_BLENDMODE_NONE) {
+            data->glDisable(GL_BLEND);
+        } else {
+            data->glEnable(GL_BLEND);
+            if (data->GL_OES_blend_func_separate_supported) {
+                data->glBlendFuncSeparateOES(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
+                                             GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
+                                             GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
+                                             GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
+            } else {
+                data->glBlendFunc(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
+                                  GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
+            }
+            if (data->GL_OES_blend_equation_separate_supported) {
+                data->glBlendEquationSeparateOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)),
+                                                 GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
+            } else if (data->GL_OES_blend_subtract_supported) {
+                data->glBlendEquationOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
+            }
+        }
+        data->drawstate.blend = blend;
+    }
+
+    if ((cmd->data.draw.texture != NULL) != data->drawstate.texturing) {
+        if (cmd->data.draw.texture == NULL) {
+            data->glDisable(GL_TEXTURE_2D);
+            data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+            data->drawstate.texturing = SDL_FALSE;
+        } else {
+            data->glEnable(GL_TEXTURE_2D);
+            data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+            data->drawstate.texturing = SDL_TRUE;
+        }
+    }
+}
+
+static void
+SetCopyState(GLES_RenderData *data, const SDL_RenderCommand *cmd)
+{
+    SDL_Texture *texture = cmd->data.draw.texture;
+    SetDrawState(data, cmd);
+
+    if (texture != data->drawstate.texture) {
+        GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
+        data->glBindTexture(GL_TEXTURE_2D, texturedata->texture);
+        data->drawstate.texture = texture;
+    }
+}
+
+static int
+GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+
+    if (GLES_ActivateRenderer(renderer) < 0) {
+        return -1;
+    }
+
+    data->drawstate.target = renderer->target;
+
+    if (!renderer->target) {
+        int w, h;
+        SDL_GL_GetDrawableSize(renderer->window, &w, &h);
+        if ((w != data->drawstate.drawablew) || (h != data->drawstate.drawableh)) {
+            data->drawstate.viewport_dirty = SDL_TRUE;  // if the window dimensions changed, invalidate the current viewport, etc.
+            data->drawstate.cliprect_dirty = SDL_TRUE;
+            data->drawstate.drawablew = w;
+            data->drawstate.drawableh = h;
+        }
+
+    }
+
+    while (cmd) {
+        switch (cmd->command) {
+            case SDL_RENDERCMD_SETDRAWCOLOR: {
+                break;  /* not used in this render backend. */
+            }
+
+            case SDL_RENDERCMD_SETVIEWPORT: {
+                SDL_Rect *viewport = &data->drawstate.viewport;
+                if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) {
+                    SDL_copyp(viewport, &cmd->data.viewport.rect);
+                    data->drawstate.viewport_dirty = SDL_TRUE;
+                }
+                break;
+            }
+
+            case SDL_RENDERCMD_SETCLIPRECT: {
+                const SDL_Rect *rect = &cmd->data.cliprect.rect;
+                if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
+                    data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
+                    data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+                }
+                if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof(*rect)) != 0) {
+                    SDL_copyp(&data->drawstate.cliprect, rect);
+                    data->drawstate.cliprect_dirty = SDL_TRUE;
+                }
+                break;
+            }
+
+            case SDL_RENDERCMD_CLEAR: {
+                const Uint8 r = cmd->data.color.r;
+                const Uint8 g = cmd->data.color.g;
+                const Uint8 b = cmd->data.color.b;
+                const Uint8 a = cmd->data.color.a;
+                const Uint32 color = (((Uint32)a << 24) | (r << 16) | (g << 8) | b);
+                if (color != data->drawstate.clear_color) {
+                    const GLfloat fr = ((GLfloat) r) * inv255f;
+                    const GLfloat fg = ((GLfloat) g) * inv255f;
+                    const GLfloat fb = ((GLfloat) b) * inv255f;
+                    const GLfloat fa = ((GLfloat) a) * inv255f;
+                    data->glClearColor(fr, fg, fb, fa);
+                    data->drawstate.clear_color = color;
+                }
+
+                if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) {
+                    data->glDisable(GL_SCISSOR_TEST);
+                    data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled;
+                }
+
+                data->glClear(GL_COLOR_BUFFER_BIT);
+
+                break;
+            }
+
+            case SDL_RENDERCMD_DRAW_POINTS: {
+                const size_t count = cmd->data.draw.count;
+                const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+                SetDrawState(data, cmd);
+                data->glVertexPointer(2, GL_FLOAT, 0, verts);
+                data->glDrawArrays(GL_POINTS, 0, (GLsizei) count);
+                break;
+            }
+
+            case SDL_RENDERCMD_DRAW_LINES: {
+                const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+                const size_t count = cmd->data.draw.count;
+                SDL_assert(count >= 2);
+                SetDrawState(data, cmd);
+                data->glVertexPointer(2, GL_FLOAT, 0, verts);
+                data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count);
+                break;
+            }
+
+            case SDL_RENDERCMD_FILL_RECTS: /* unused */
+                break;
+
+            case SDL_RENDERCMD_COPY: /* unused */
+                break;
+
+            case SDL_RENDERCMD_COPY_EX: /* unused */
+                break;
+
+            case SDL_RENDERCMD_GEOMETRY: {
+                const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+                SDL_Texture *texture = cmd->data.draw.texture;
+                const size_t count = cmd->data.draw.count;
+                int stride = (2 + 4 + (texture ? 2 : 0)) * sizeof (float);
+
+                if (texture) {
+                    SetCopyState(data, cmd);
+                } else {
+                    SetDrawState(data, cmd);
+                }
+
+                data->glEnableClientState(GL_COLOR_ARRAY);
+
+                data->glVertexPointer(2, GL_FLOAT, stride, verts);
+                data->glColorPointer(4, GL_FLOAT, stride, verts + 2);
+                if (texture) {
+                    data->glTexCoordPointer(2, GL_FLOAT, stride, verts + 2 + 4);
+                }
+
+                data->glDrawArrays(GL_TRIANGLES, 0, (GLsizei) count);
+
+                data->glDisableClientState(GL_COLOR_ARRAY);
+                break;
+            }
+
+            case SDL_RENDERCMD_NO_OP:
+                break;
+        }
+
+        cmd = cmd->next;
+    }
+
+    return 0;
+}
+
+static int
+GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
+                      Uint32 pixel_format, void * pixels, int pitch)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+    Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
+    void *temp_pixels;
+    int temp_pitch;
+    Uint8 *src, *dst, *tmp;
+    int w, h, length, rows;
+    int status;
+
+    GLES_ActivateRenderer(renderer);
+
+    temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
+    temp_pixels = SDL_malloc(rect->h * temp_pitch);
+    if (!temp_pixels) {
+        return SDL_OutOfMemory();
+    }
+
+    SDL_GetRendererOutputSize(renderer, &w, &h);
+
+    data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+    data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
+                       rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
+
+    /* Flip the rows to be top-down if necessary */
+    if (!renderer->target) {
+        SDL_bool isstack;
+        length = rect->w * SDL_BYTESPERPIXEL(temp_format);
+        src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
+        dst = (Uint8*)temp_pixels;
+        tmp = SDL_small_alloc(Uint8, length, &isstack);
+        rows = rect->h / 2;
+        while (rows--) {
+            SDL_memcpy(tmp, dst, length);
+            SDL_memcpy(dst, src, length);
+            SDL_memcpy(src, tmp, length);
+            dst += temp_pitch;
+            src -= temp_pitch;
+        }
+        SDL_small_free(tmp, isstack);
+    }
+
+    status = SDL_ConvertPixels(rect->w, rect->h,
+                               temp_format, temp_pixels, temp_pitch,
+                               pixel_format, pixels, pitch);
+    SDL_free(temp_pixels);
+
+    return status;
+}
+
+static int
+GLES_RenderPresent(SDL_Renderer * renderer)
+{
+    GLES_ActivateRenderer(renderer);
+
+    return SDL_GL_SwapWindowWithResult(renderer->window);
+}
+
+static void
+GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata;
+
+    GLES_TextureData *data = (GLES_TextureData *) texture->driverdata;
+
+    GLES_ActivateRenderer(renderer);
+
+    if (renderdata->drawstate.texture == texture) {
+        renderdata->drawstate.texture = NULL;
+    }
+    if (renderdata->drawstate.target == texture) {
+        renderdata->drawstate.target = NULL;
+    }
+
+    if (!data) {
+        return;
+    }
+    if (data->texture) {
+        renderdata->glDeleteTextures(1, &data->texture);
+    }
+    SDL_free(data->pixels);
+    SDL_free(data);
+    texture->driverdata = NULL;
+}
+
+static void
+GLES_DestroyRenderer(SDL_Renderer * renderer)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+
+    if (data) {
+        if (data->context) {
+            while (data->framebuffers) {
+               GLES_FBOList *nextnode = data->framebuffers->next;
+               data->glDeleteFramebuffersOES(1, &data->framebuffers->FBO);
+               SDL_free(data->framebuffers);
+               data->framebuffers = nextnode;
+            }
+            SDL_GL_DeleteContext(data->context);
+        }
+        SDL_free(data);
+    }
+    SDL_free(renderer);
+}
+
+static int GLES_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+    GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
+    GLES_ActivateRenderer(renderer);
+
+    data->glEnable(GL_TEXTURE_2D);
+    data->glBindTexture(texturedata->type, texturedata->texture);
+
+    data->drawstate.texture = texture;
+    data->drawstate.texturing = SDL_TRUE;
+
+    if (texw) {
+        *texw = (float)texturedata->texw;
+    }
+    if (texh) {
+        *texh = (float)texturedata->texh;
+    }
+
+    return 0;
+}
+
+static int GLES_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
+{
+    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+    GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
+    GLES_ActivateRenderer(renderer);
+    data->glDisable(texturedata->type);
+
+    data->drawstate.texture = NULL;
+    data->drawstate.texturing = SDL_FALSE;
+
+    return 0;
+}
+
+static int
+GLES_SetVSync(SDL_Renderer * renderer, const int vsync)
+{
+    int retval;
+    if (vsync) {
+        retval = SDL_GL_SetSwapInterval(1);
+    } else {
+        retval = SDL_GL_SetSwapInterval(0);
+    }
+    if (retval != 0) {
+        return retval;
+    }
+    if (SDL_GL_GetSwapInterval() > 0) {
+        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+    } else {
+        renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC;
+    }
+    return retval;
+}
+
+
+static SDL_Renderer *
+GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
+{
+    SDL_Renderer *renderer;
+    GLES_RenderData *data;
+    GLint value;
+    Uint32 window_flags;
+    int profile_mask = 0, major = 0, minor = 0;
+    SDL_bool changed_window = SDL_FALSE;
+
+    SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
+    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
+    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
+
+    window_flags = SDL_GetWindowFlags(window);
+    if (!(window_flags & SDL_WINDOW_OPENGL) ||
+        profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
+
+        changed_window = SDL_TRUE;
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
+
+        if (SDL_RecreateWindow(window, (window_flags & ~(SDL_WINDOW_VULKAN | SDL_WINDOW_METAL)) | SDL_WINDOW_OPENGL) < 0) {
+            goto error;
+        }
+    }
+
+    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+    if (!renderer) {
+        SDL_OutOfMemory();
+        goto error;
+    }
+
+    data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
+    if (!data) {
+        GLES_DestroyRenderer(renderer);
+        SDL_OutOfMemory();
+        goto error;
+    }
+
+    renderer->WindowEvent = GLES_WindowEvent;
+    renderer->GetOutputSize = GLES_GetOutputSize;
+    renderer->SupportsBlendMode = GLES_SupportsBlendMode;
+    renderer->CreateTexture = GLES_CreateTexture;
+    renderer->UpdateTexture = GLES_UpdateTexture;
+    renderer->LockTexture = GLES_LockTexture;
+    renderer->UnlockTexture = GLES_UnlockTexture;
+    renderer->SetTextureScaleMode = GLES_SetTextureScaleMode;
+    renderer->SetRenderTarget = GLES_SetRenderTarget;
+    renderer->QueueSetViewport = GLES_QueueSetViewport;
+    renderer->QueueSetDrawColor = GLES_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
+    renderer->QueueDrawPoints = GLES_QueueDrawPoints;
+    renderer->QueueDrawLines = GLES_QueueDrawLines;
+    renderer->QueueGeometry = GLES_QueueGeometry;
+    renderer->RunCommandQueue = GLES_RunCommandQueue;
+    renderer->RenderReadPixels = GLES_RenderReadPixels;
+    renderer->RenderPresent = GLES_RenderPresent;
+    renderer->DestroyTexture = GLES_DestroyTexture;
+    renderer->DestroyRenderer = GLES_DestroyRenderer;
+    renderer->SetVSync = GLES_SetVSync;
+    renderer->GL_BindTexture = GLES_BindTexture;
+    renderer->GL_UnbindTexture = GLES_UnbindTexture;
+    renderer->info = GLES_RenderDriver.info;
+    renderer->info.flags = SDL_RENDERER_ACCELERATED;
+    renderer->driverdata = data;
+    renderer->window = window;
+
+    data->context = SDL_GL_CreateContext(window);
+    if (!data->context) {
+        GLES_DestroyRenderer(renderer);
+        goto error;
+    }
+    if (SDL_GL_MakeCurrent(window, data->context) < 0) {
+        GLES_DestroyRenderer(renderer);
+        goto error;
+    }
+
+    if (GLES_LoadFunctions(data) < 0) {
+        GLES_DestroyRenderer(renderer);
+        goto error;
+    }
+
+    if (flags & SDL_RENDERER_PRESENTVSYNC) {
+        SDL_GL_SetSwapInterval(1);
+    } else {
+        SDL_GL_SetSwapInterval(0);
+    }
+    if (SDL_GL_GetSwapInterval() > 0) {
+        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+    }
+
+    value = 0;
+    data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
+    renderer->info.max_texture_width = value;
+    value = 0;
+    data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
+    renderer->info.max_texture_height = value;
+
+    /* Android does not report GL_OES_framebuffer_object but the functionality seems to be there anyway */
+    if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object") || data->glGenFramebuffersOES) {
+        data->GL_OES_framebuffer_object_supported = SDL_TRUE;
+        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
+
+        value = 0;
+        data->glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &value);
+        data->window_framebuffer = (GLuint)value;
+    }
+    data->framebuffers = NULL;
+
+    if (SDL_GL_ExtensionSupported("GL_OES_blend_func_separate")) {
+        data->GL_OES_blend_func_separate_supported = SDL_TRUE;
+    }
+    if (SDL_GL_ExtensionSupported("GL_OES_blend_equation_separate")) {
+        data->GL_OES_blend_equation_separate_supported = SDL_TRUE;
+    }
+    if (SDL_GL_ExtensionSupported("GL_OES_blend_subtract")) {
+        data->GL_OES_blend_subtract_supported = SDL_TRUE;
+    }
+
+    /* Set up parameters for rendering */
+    data->glDisable(GL_DEPTH_TEST);
+    data->glDisable(GL_CULL_FACE);
+
+    data->glMatrixMode(GL_MODELVIEW);
+    data->glLoadIdentity();
+
+    data->glEnableClientState(GL_VERTEX_ARRAY);
+    data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+    data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+
+    data->drawstate.blend = SDL_BLENDMODE_INVALID;
+    data->drawstate.color = 0xFFFFFFFF;
+    data->drawstate.clear_color = 0xFFFFFFFF;
+
+    return renderer;
+
+error:
+    if (changed_window) {
+        /* Uh oh, better try to put it back... */
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
+        SDL_RecreateWindow(window, window_flags);
+    }
+    return NULL;
+}
+
+SDL_RenderDriver GLES_RenderDriver = {
+    GLES_CreateRenderer,
+    {
+     "opengles",
+     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
+     1,
+     {SDL_PIXELFORMAT_ABGR8888},
+     0,
+     0
+    }
+};
+
+#endif /* SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 1 - 1
src/video/SDL_sysvideo.h

@@ -431,7 +431,7 @@ struct SDL_VideoDevice
     struct SDL_EGL_VideoData *egl_data;
 #endif
 
-#if SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
     struct SDL_PrivateGLESData *gles_data;
 #endif
 

+ 13 - 5
src/video/SDL_video.c

@@ -37,6 +37,10 @@
 #include "SDL_opengl.h"
 #endif /* SDL_VIDEO_OPENGL */
 
+#if SDL_VIDEO_OPENGL_ES && !SDL_VIDEO_OPENGL
+#include "SDL_opengles.h"
+#endif /* SDL_VIDEO_OPENGL_ES && !SDL_VIDEO_OPENGL */
+
 /* GL and GLES2 headers conflict on Linux 32 bits */
 #if SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL
 #include "SDL_opengles2.h"
@@ -3436,7 +3440,7 @@ SDL_GL_UnloadLibrary(void)
     }
 }
 
-#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
 static SDL_INLINE SDL_bool
 isAtLeastGL3(const char *verstr)
 {
@@ -3447,7 +3451,7 @@ isAtLeastGL3(const char *verstr)
 SDL_bool
 SDL_GL_ExtensionSupported(const char *extension)
 {
-#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
     const char *extensions;
     const char *start;
@@ -3539,7 +3543,7 @@ SDL_GL_DeduceMaxSupportedESProfile(int* major, int* minor)
 {
 /* THIS REQUIRES AN EXISTING GL CONTEXT THAT HAS BEEN MADE CURRENT. */
 /*  Please refer to https://bugzilla.libsdl.org/show_bug.cgi?id=3725 for discussion. */
-#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
     /* XXX This is fragile; it will break in the event of release of
      * new versions of OpenGL ES.
      */
@@ -3593,6 +3597,10 @@ SDL_GL_ResetAttributes()
     _this->gl_config.major_version = 2;
     _this->gl_config.minor_version = 0;
     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
+#elif SDL_VIDEO_OPENGL_ES
+    _this->gl_config.major_version = 1;
+    _this->gl_config.minor_version = 1;
+    _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
 #endif
 
     if (_this->GL_DefaultProfileConfig) {
@@ -3613,7 +3621,7 @@ SDL_GL_ResetAttributes()
 int
 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
 {
-#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
     int retval;
 
     if (!_this) {
@@ -3737,7 +3745,7 @@ SDL_GL_SetAttribute(SDL_GLattr attr, int value)
 int
 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
 {
-#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
     GLenum (APIENTRY *glGetErrorFunc) (void);
     GLenum attrib = 0;
     GLenum error = 0;

+ 1 - 1
src/video/uikit/SDL_uikitevents.m

@@ -148,7 +148,7 @@ UIKit_PumpEvents(_THIS)
     } while(result == kCFRunLoopRunHandledSource);
 
     /* See the comment in the function definition. */
-#if SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
     UIKit_GL_RestoreCurrentContext();
 #endif
 }

+ 2 - 2
src/video/uikit/SDL_uikitopengles.h

@@ -21,7 +21,7 @@
 #ifndef SDL_uikitopengles_
 #define SDL_uikitopengles_
 
-#if SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
 
 #include "../SDL_sysvideo.h"
 
@@ -37,7 +37,7 @@ extern int UIKit_GL_LoadLibrary(_THIS, const char *path);
 
 extern void UIKit_GL_RestoreCurrentContext(void);
 
-#endif /* SDL_VIDEO_OPENGL_ES2 */
+#endif // SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
 
 #endif /* SDL_uikitopengles_ */
 

+ 1 - 1
src/video/uikit/SDL_uikitopengles.m

@@ -20,7 +20,7 @@
 */
 #include "../../SDL_internal.h"
 
-#if SDL_VIDEO_DRIVER_UIKIT && SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2)
 
 #include "SDL_uikitopengles.h"
 #import "SDL_uikitopenglview.h"

+ 2 - 2
src/video/uikit/SDL_uikitopenglview.h

@@ -19,7 +19,7 @@
   3. This notice may not be removed or altered from any source distribution.
 */
 
-#if SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
 
 #import <UIKit/UIKit.h>
 #import <OpenGLES/EAGL.h>
@@ -59,6 +59,6 @@
 
 @end
 
-#endif /* SDL_VIDEO_OPENGL_ES2 */
+#endif // SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
 
 /* vi: set ts=4 sw=4 expandtab: */

+ 1 - 1
src/video/uikit/SDL_uikitopenglview.m

@@ -20,7 +20,7 @@
 */
 #include "../../SDL_internal.h"
 
-#if SDL_VIDEO_DRIVER_UIKIT && SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2)
 
 #include <OpenGLES/EAGLDrawable.h>
 #include <OpenGLES/ES2/glext.h>

+ 1 - 1
src/video/uikit/SDL_uikitvideo.m

@@ -113,7 +113,7 @@ UIKit_CreateDevice(void)
         device->HasClipboardText = UIKit_HasClipboardText;
 
         /* OpenGL (ES) functions */
-#if SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
         device->GL_MakeCurrent      = UIKit_GL_MakeCurrent;
         device->GL_GetDrawableSize  = UIKit_GL_GetDrawableSize;
         device->GL_SwapWindow       = UIKit_GL_SwapWindow;

+ 1 - 1
src/video/uikit/SDL_uikitviewcontroller.m

@@ -176,7 +176,7 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
     /* Don't run the game loop while a messagebox is up */
     if (!UIKit_ShowingMessageBox()) {
         /* See the comment in the function definition. */
-#if SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
         UIKit_GL_RestoreCurrentContext();
 #endif
 

+ 1 - 1
src/video/uikit/SDL_uikitwindow.m

@@ -404,7 +404,7 @@ UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
 
             /* These struct members were added in SDL 2.0.4. */
             if (versionnum >= SDL_VERSIONNUM(2,0,4)) {
-#if SDL_VIDEO_OPENGL_ES2
+#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
                 if ([data.viewcontroller.view isKindOfClass:[SDL_uikitopenglview class]]) {
                     SDL_uikitopenglview *glview = (SDL_uikitopenglview *)data.viewcontroller.view;
                     info->info.uikit.framebuffer = glview.drawableFramebuffer;

+ 1 - 1
src/video/x11/SDL_x11window.c

@@ -648,7 +648,7 @@ X11_CreateWindow(_THIS, SDL_Window * window)
     }
     windowdata = (SDL_WindowData *) window->driverdata;
 
-#if SDL_VIDEO_OPENGL_ES2 || SDL_VIDEO_OPENGL_EGL
+#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 || SDL_VIDEO_OPENGL_EGL
     if ((window->flags & SDL_WINDOW_OPENGL) && 
         ((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) ||
          SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE))

+ 1 - 0
test/CMakeLists.txt

@@ -125,6 +125,7 @@ add_sdl_test_executable(testgamecontroller NEEDS_RESOURCES testgamecontroller.c
 add_sdl_test_executable(testgeometry testgeometry.c testutils.c)
 add_sdl_test_executable(testgesture testgesture.c)
 add_sdl_test_executable(testgl2 testgl2.c)
+add_sdl_test_executable(testgles testgles.c)
 add_sdl_test_executable(testgles2 testgles2.c)
 add_sdl_test_executable(testhaptic testhaptic.c)
 add_sdl_test_executable(testhotplug testhotplug.c)

+ 4 - 0
test/Makefile.in

@@ -84,6 +84,7 @@ TARGETS = \
 
 
 @OPENGL_TARGETS@ += testgl2$(EXE) testshader$(EXE)
+@OPENGLES1_TARGETS@ += testgles$(EXE)
 @OPENGLES2_TARGETS@ += testgles2$(EXE)
 
 
@@ -207,6 +208,9 @@ testgesture$(EXE): $(srcdir)/testgesture.c
 testgl2$(EXE): $(srcdir)/testgl2.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @MATHLIB@
 
+testgles$(EXE): $(srcdir)/testgles.c
+	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @GLESLIB@ @MATHLIB@
+
 testgles2$(EXE): $(srcdir)/testgles2.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @MATHLIB@
 

+ 35 - 0
test/configure

@@ -624,6 +624,7 @@ GLESLIB
 GLLIB
 OPENGL_TARGETS
 OPENGLES2_TARGETS
+OPENGLES1_TARGETS
 CPP
 XMKMF
 SDL3_CONFIG
@@ -4573,6 +4574,33 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_opengl" >&5
 printf "%s\n" "$have_opengl" >&6; }
 
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OpenGL ES support" >&5
+printf %s "checking for OpenGL ES support... " >&6; }
+have_opengles=no
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+ #include "SDL_opengles.h"
+ #ifndef SDL_VIDEO_OPENGL_ES
+ #error SDL_VIDEO_OPENGL_ES
+ #endif
+
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+  have_opengles=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_opengles" >&5
+printf "%s\n" "$have_opengles" >&6; }
+
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OpenGL ES2 support" >&5
 printf %s "checking for OpenGL ES2 support... " >&6; }
 have_opengles2=no
@@ -4603,8 +4631,14 @@ printf "%s\n" "$have_opengles2" >&6; }
 GLLIB=""
 GLESLIB=""
 GLES2LIB=""
+OPENGLES1_TARGETS="UNUSED"
 OPENGLES2_TARGETS="UNUSED"
 OPENGL_TARGETS="UNUSED"
+if test x$have_opengles = xyes; then
+    CFLAGS="$CFLAGS -DHAVE_OPENGLES"
+    GLESLIB="$XPATH -lGLESv1_CM"
+    OPENGLES1_TARGETS="TARGETS"
+fi
 if test x$have_opengles2 = xyes; then
     CFLAGS="$CFLAGS -DHAVE_OPENGLES2"
     #GLES2LIB="$XPATH -lGLESv2"
@@ -4783,6 +4817,7 @@ esac
 
 
 
+
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for TTF_Init in -lSDL3_ttf" >&5
 printf %s "checking for TTF_Init in -lSDL3_ttf... " >&6; }
 if test ${ac_cv_lib_SDL3_ttf_TTF_Init+y}

+ 18 - 0
test/configure.ac

@@ -127,6 +127,17 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
 ]],[])], [have_opengl=yes],[])
 AC_MSG_RESULT($have_opengl)
 
+dnl Check for OpenGL ES
+AC_MSG_CHECKING(for OpenGL ES support)
+have_opengles=no
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include "SDL_opengles.h"
+ #ifndef SDL_VIDEO_OPENGL_ES
+ #error SDL_VIDEO_OPENGL_ES
+ #endif
+]],[])] ,[have_opengles=yes],[])
+AC_MSG_RESULT($have_opengles)
+
 dnl Check for OpenGL ES2
 AC_MSG_CHECKING(for OpenGL ES2 support)
 have_opengles2=no
@@ -141,8 +152,14 @@ AC_MSG_RESULT($have_opengles2)
 GLLIB=""
 GLESLIB=""
 GLES2LIB=""
+OPENGLES1_TARGETS="UNUSED"
 OPENGLES2_TARGETS="UNUSED"
 OPENGL_TARGETS="UNUSED"
+if test x$have_opengles = xyes; then
+    CFLAGS="$CFLAGS -DHAVE_OPENGLES"
+    GLESLIB="$XPATH -lGLESv1_CM"
+    OPENGLES1_TARGETS="TARGETS"
+fi
 if test x$have_opengles2 = xyes; then
     CFLAGS="$CFLAGS -DHAVE_OPENGLES2"
     #GLES2LIB="$XPATH -lGLESv2"
@@ -228,6 +245,7 @@ case "$host" in
     	;;
 esac
 
+AC_SUBST(OPENGLES1_TARGETS)
 AC_SUBST(OPENGLES2_TARGETS)
 AC_SUBST(OPENGL_TARGETS)
 AC_SUBST(GLLIB)

+ 355 - 0
test/testgles.c

@@ -0,0 +1,355 @@
+/*
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely.
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "SDL_test_common.h"
+
+#if defined(__IPHONEOS__) || defined(__ANDROID__)
+#define HAVE_OPENGLES
+#endif
+
+#ifdef HAVE_OPENGLES
+
+#include "SDL_opengles.h"
+
+static SDLTest_CommonState *state;
+static SDL_GLContext *context = NULL;
+static int depth = 16;
+
+/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
+static void
+quit(int rc)
+{
+    int i;
+
+    if (context != NULL) {
+        for (i = 0; i < state->num_windows; i++) {
+            if (context[i]) {
+                SDL_GL_DeleteContext(context[i]);
+            }
+        }
+
+        SDL_free(context);
+    }
+
+    SDLTest_CommonQuit(state);
+    exit(rc);
+}
+
+static void
+Render()
+{
+    static GLubyte color[8][4] = { {255, 0, 0, 0},
+    {255, 0, 0, 255},
+    {0, 255, 0, 255},
+    {0, 255, 0, 255},
+    {0, 255, 0, 255},
+    {255, 255, 255, 255},
+    {255, 0, 255, 255},
+    {0, 0, 255, 255}
+    };
+    static GLfloat cube[8][3] = { {0.5, 0.5, -0.5},
+    {0.5f, -0.5f, -0.5f},
+    {-0.5f, -0.5f, -0.5f},
+    {-0.5f, 0.5f, -0.5f},
+    {-0.5f, 0.5f, 0.5f},
+    {0.5f, 0.5f, 0.5f},
+    {0.5f, -0.5f, 0.5f},
+    {-0.5f, -0.5f, 0.5f}
+    };
+    static GLubyte indices[36] = { 0, 3, 4,
+        4, 5, 0,
+        0, 5, 6,
+        6, 1, 0,
+        6, 7, 2,
+        2, 1, 6,
+        7, 4, 3,
+        3, 2, 7,
+        5, 4, 7,
+        7, 6, 5,
+        2, 3, 1,
+        3, 0, 1
+    };
+
+
+    /* Do our drawing, too. */
+    glClearColor(0.0, 0.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    /* Draw the cube */
+    glColorPointer(4, GL_UNSIGNED_BYTE, 0, color);
+    glEnableClientState(GL_COLOR_ARRAY);
+    glVertexPointer(3, GL_FLOAT, 0, cube);
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);
+
+    glMatrixMode(GL_MODELVIEW);
+    glRotatef(5.0, 1.0, 1.0, 1.0);
+}
+
+int
+main(int argc, char *argv[])
+{
+    int fsaa, accel;
+    int value;
+    int i, done;
+    SDL_DisplayMode mode;
+    SDL_Event event;
+    Uint32 then, now, frames;
+    int status;
+
+    /* Enable standard application logging */
+    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
+
+    /* Initialize parameters */
+    fsaa = 0;
+    accel = 0;
+
+    /* Initialize test framework */
+    state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
+    if (!state) {
+        return 1;
+    }
+    for (i = 1; i < argc;) {
+        int consumed;
+
+        consumed = SDLTest_CommonArg(state, i);
+        if (consumed == 0) {
+            if (SDL_strcasecmp(argv[i], "--fsaa") == 0) {
+                ++fsaa;
+                consumed = 1;
+            } else if (SDL_strcasecmp(argv[i], "--accel") == 0) {
+                ++accel;
+                consumed = 1;
+            } else if (SDL_strcasecmp(argv[i], "--zdepth") == 0) {
+                i++;
+                if (!argv[i]) {
+                    consumed = -1;
+                } else {
+                    depth = SDL_atoi(argv[i]);
+                    consumed = 1;
+                }
+            } else {
+                consumed = -1;
+            }
+        }
+        if (consumed < 0) {
+            static const char *options[] = { "[--fsaa]", "[--accel]", "[--zdepth %d]", NULL };
+            SDLTest_CommonLogUsage(state, argv[0], options);
+            quit(1);
+        }
+        i += consumed;
+    }
+
+    /* Set OpenGL parameters */
+    state->window_flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS;
+    state->gl_red_size = 5;
+    state->gl_green_size = 5;
+    state->gl_blue_size = 5;
+    state->gl_depth_size = depth;
+    state->gl_major_version = 1;
+    state->gl_minor_version = 1;
+    state->gl_profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
+    if (fsaa) {
+        state->gl_multisamplebuffers=1;
+        state->gl_multisamplesamples=fsaa;
+    }
+    if (accel) {
+        state->gl_accelerated=1;
+    }
+    if (!SDLTest_CommonInit(state)) {
+        quit(2);
+    }
+
+    context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context));
+    if (context == NULL) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
+        quit(2);
+    }
+
+    /* Create OpenGL ES contexts */
+    for (i = 0; i < state->num_windows; i++) {
+        context[i] = SDL_GL_CreateContext(state->windows[i]);
+        if (!context[i]) {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GL_CreateContext(): %s\n", SDL_GetError());
+            quit(2);
+        }
+    }
+
+    if (state->render_flags & SDL_RENDERER_PRESENTVSYNC) {
+        SDL_GL_SetSwapInterval(1);
+    } else {
+        SDL_GL_SetSwapInterval(0);
+    }
+
+    SDL_GetCurrentDisplayMode(0, &mode);
+    SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode.format));
+    SDL_Log("\n");
+    SDL_Log("Vendor     : %s\n", glGetString(GL_VENDOR));
+    SDL_Log("Renderer   : %s\n", glGetString(GL_RENDERER));
+    SDL_Log("Version    : %s\n", glGetString(GL_VERSION));
+    SDL_Log("Extensions : %s\n", glGetString(GL_EXTENSIONS));
+    SDL_Log("\n");
+
+    status = SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value);
+    if (!status) {
+        SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d\n", 5, value);
+    } else {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_RED_SIZE: %s\n",
+                SDL_GetError());
+    }
+    status = SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value);
+    if (!status) {
+        SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d\n", 5, value);
+    } else {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_GREEN_SIZE: %s\n",
+                SDL_GetError());
+    }
+    status = SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value);
+    if (!status) {
+        SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d\n", 5, value);
+    } else {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_BLUE_SIZE: %s\n",
+                SDL_GetError());
+    }
+    status = SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value);
+    if (!status) {
+        SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d\n", depth, value);
+    } else {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_DEPTH_SIZE: %s\n",
+                SDL_GetError());
+    }
+    if (fsaa) {
+        status = SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value);
+        if (!status) {
+            SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value);
+        } else {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s\n",
+                    SDL_GetError());
+        }
+        status = SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value);
+        if (!status) {
+            SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa,
+                   value);
+        } else {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_MULTISAMPLESAMPLES: %s\n",
+                    SDL_GetError());
+        }
+    }
+    if (accel) {
+        status = SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value);
+        if (!status) {
+            SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d\n", value);
+        } else {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL_GL_ACCELERATED_VISUAL: %s\n",
+                    SDL_GetError());
+        }
+    }
+
+    /* Set rendering settings for each context */
+    for (i = 0; i < state->num_windows; ++i) {
+        float aspectAdjust;
+
+        status = SDL_GL_MakeCurrent(state->windows[i], context[i]);
+        if (status) {
+            SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError());
+
+            /* Continue for next window */
+            continue;
+        }
+
+        aspectAdjust = (4.0f / 3.0f) / ((float)state->window_w / state->window_h);
+        glViewport(0, 0, state->window_w, state->window_h);
+        glMatrixMode(GL_PROJECTION);
+        glLoadIdentity();
+        glOrthof(-2.0, 2.0, -2.0 * aspectAdjust, 2.0 * aspectAdjust, -20.0, 20.0);
+        glMatrixMode(GL_MODELVIEW);
+        glLoadIdentity();
+        glEnable(GL_DEPTH_TEST);
+        glDepthFunc(GL_LESS);
+        glShadeModel(GL_SMOOTH);
+    }
+
+    /* Main render loop */
+    frames = 0;
+    then = SDL_GetTicks();
+    done = 0;
+    while (!done) {
+        /* Check for events */
+        ++frames;
+        while (SDL_PollEvent(&event)) {
+            switch (event.type) {
+            case SDL_WINDOWEVENT:
+                switch (event.window.event) {
+                    case SDL_WINDOWEVENT_RESIZED:
+                        for (i = 0; i < state->num_windows; ++i) {
+                            if (event.window.windowID == SDL_GetWindowID(state->windows[i])) {
+                                status = SDL_GL_MakeCurrent(state->windows[i], context[i]);
+                                if (status) {
+                                    SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError());
+                                    break;
+                                }
+                                /* Change view port to the new window dimensions */
+                                glViewport(0, 0, event.window.data1, event.window.data2);
+                                /* Update window content */
+                                Render();
+                                SDL_GL_SwapWindow(state->windows[i]);
+                                break;
+                            }
+                        }
+                        break;
+                }
+            }
+            SDLTest_CommonEvent(state, &event, &done);
+        }
+        for (i = 0; i < state->num_windows; ++i) {
+            if (state->windows[i] == NULL)
+                continue;
+            status = SDL_GL_MakeCurrent(state->windows[i], context[i]);
+            if (status) {
+                SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError());
+
+                /* Continue for next window */
+                continue;
+            }
+            Render();
+            SDL_GL_SwapWindow(state->windows[i]);
+        }
+    }
+
+    /* Print out some timing information */
+    now = SDL_GetTicks();
+    if (now > then) {
+        SDL_Log("%2.2f frames per second\n",
+               ((double) frames * 1000) / (now - then));
+    }
+#if !defined(__ANDROID__)
+    quit(0);
+#endif        
+    return 0;
+}
+
+#else /* HAVE_OPENGLES */
+
+int
+main(int argc, char *argv[])
+{
+    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No OpenGL ES support on this system\n");
+    return 1;
+}
+
+#endif /* HAVE_OPENGLES */
+
+/* vi: set ts=4 sw=4 expandtab: */