diff -ru a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt	2026-07-31 14:04:53.195646458 +0200
+++ b/CMakeLists.txt	2026-07-31 14:05:05.703429751 +0200
@@ -46,9 +46,27 @@
 
 add_compile_options(-fsigned-char -fno-strict-aliasing)
 
-# Find OpenGL
+# Find OpenGL. Android has no desktop GL/GLX for CMake's FindOpenGL module
+# to find - build GL4ES from source instead (translates this file's
+# desktop-style GL calls into GLES/EGL; it links GLESv2/EGL itself, so
+# the engine doesn't need to link them directly), via add_subdirectory
+# rather than a prebuilt .so: ANDROID_GL4ES_DIR (passed in by
+# android/app/build.gradle, same as ANDROID_PREBUILT_DIR) is a scratch,
+# patched copy of android/gl4es-src/ staged by
+# build-image/prepare-android-project.sh (mirrors how this file itself is
+# staged/patched before Gradle ever sees it) - building it as part of this
+# same CMake configure means Gradle's own incremental CMake/Ninja build
+# only recompiles it when gl4es-src/gl4es-patches actually changed, same
+# as this file, instead of needing a full build-image rebuild for every
+# gl4es-patches change.
 if(ENABLE_OPENGL)
-	find_package(OpenGL REQUIRED)
+	if(ANDROID)
+		add_subdirectory(${ANDROID_GL4ES_DIR} ${CMAKE_BINARY_DIR}/gl4es-build)
+		set(OPENGL_INCLUDE_DIRS ${ANDROID_GL4ES_DIR}/include)
+		set(OPENGL_LIBRARIES GL)
+	else()
+		find_package(OpenGL REQUIRED)
+	endif()
 	add_definitions(-DUSE_OPENGL)
 	if(WIN32)
 		list(APPEND OPENGL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/build_ext/built_glew/include)
