--- a/src/MacSrc/OpenGL.cc
+++ b/src/MacSrc/OpenGL.cc
@@ -20,6 +20,24 @@
 #include <SDL_opengl.h>
 #endif
 
+#ifdef __ANDROID__
+// GL4ES's glPointSize()/custom-shader interop goes through the same kind
+// of shader-source rewrite as its alpha-test emulation (see
+// init_opengl() below) - avoid relying on it. GLES point size instead
+// comes from a "pointSize" uniform, written to gl_PointSize in
+// android/gles-shaders/main.vert. opengl_begin_stars() (the only
+// glPointSize() call site) now binds the star shader first, so
+// GL_CURRENT_PROGRAM here is always correct.
+#define glPointSize questshock_glPointSize
+static void questshock_glPointSize(GLfloat size) {
+    GLint program = 0;
+    glGetIntegerv(GL_CURRENT_PROGRAM, &program);
+    GLint loc = glGetUniformLocation(program, "pointSize");
+    if (loc >= 0)
+        glUniform1f(loc, size);
+}
+#endif // __ANDROID__
+
 extern "C" {
 #include "mainloop.h"
 #include "map.h"
@@ -229,6 +247,13 @@
     GLuint shaderProgram = glCreateProgram();
     glAttachShader(shaderProgram, vertShader);
     glAttachShader(shaderProgram, fragShader);
+#ifdef __ANDROID__
+    // Must be bound before linking. GL4ES routes glVertex3f() (used
+    // throughout this file below) to attribute location 0 of whatever
+    // shader is currently bound - matches
+    // android/gles-shaders/main.vert's "position" attribute.
+    glBindAttribLocation(shaderProgram, 0, "position");
+#endif
     glLinkProgram(shaderProgram);
     glUseProgram(shaderProgram);
 
@@ -313,10 +338,18 @@
 
     glEnable(GL_CULL_FACE);
     glEnable(GL_BLEND);
+#ifndef __ANDROID__
+    // GL4ES emulates both of these (alpha test, point sprites) for a
+    // custom shader by rewriting its source under the hood - a rougher
+    // edge of the library. Skip relying on that: alpha test is instead
+    // a discard in android/gles-shaders/texture.frag, and point-sprite
+    // rasterization for GL_POINTS works automatically in GLES with no
+    // enable call at all (see android/gles-shaders/star.frag).
     glEnable(GL_ALPHA_TEST);
     glEnable(GL_POINT_SPRITE);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glAlphaFunc(GL_GEQUAL, 0.05f);
+#endif
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
     CreateShader("main.vert", "texture.frag", &textureShaderProgram);
     CreateShader("main.vert", "color.frag", &colorShaderProgram);
@@ -908,9 +941,12 @@
 void opengl_begin_stars() {
     SDL_GL_MakeCurrent(window, context);
 
+    // Bind the star shader before setting the point size: on Android,
+    // questshock_glPointSize() (see the __ANDROID__ block above) needs
+    // it to already be GL_CURRENT_PROGRAM.
+    glUseProgram(starShaderProgram.shaderProgram);
     glPointSize(1.5 * (render_width / 320.0));
 
-    glUseProgram(starShaderProgram.shaderProgram);
     glUniformMatrix4fv(starShaderProgram.uniView, 1, false, IdentityMatrix);
     glUniformMatrix4fv(starShaderProgram.uniProj, 1, false, IdentityMatrix);
 
