Add a Java API for OpenGL ES 2.0.

Currently this API is hidden.

Add a test program.
diff --git a/opengl/tools/glgen/src/CType.java b/opengl/tools/glgen/src/CType.java
index 826c90d..d49e9ef 100644
--- a/opengl/tools/glgen/src/CType.java
+++ b/opengl/tools/glgen/src/CType.java
@@ -44,8 +44,12 @@
         baseType.equals("void");
     }
 
+    public boolean isConstCharPointer() {
+        return isConst && isPointer && baseType.equals("char");
+    }
+
     public boolean isTypedPointer() {
-    return isPointer() && !isVoid();
+    return isPointer() && !isVoid() && !isConstCharPointer();
     }
 
     public void setBaseType(String baseType) {
diff --git a/opengl/tools/glgen/src/GenerateGLES.java b/opengl/tools/glgen/src/GenerateGLES.java
index 60775b7..08063f3 100644
--- a/opengl/tools/glgen/src/GenerateGLES.java
+++ b/opengl/tools/glgen/src/GenerateGLES.java
@@ -70,7 +70,7 @@
 
         // Generate files
         for(String suffix: new String[] {"GLES10", "GLES10Ext",
-                "GLES11", "GLES11Ext"})
+                "GLES11", "GLES11Ext", "GLES20"})
         {
             BufferedReader spec11Reader =
                 new BufferedReader(new FileReader("specs/gles11/"
diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java
index df1177b..32d9fe7 100644
--- a/opengl/tools/glgen/src/JType.java
+++ b/opengl/tools/glgen/src/JType.java
@@ -6,6 +6,7 @@
     String baseType;
     boolean isArray;
     boolean isClass;
+    boolean isString;
 
     static HashMap<CType,JType> typeMapping = new HashMap<CType,JType>();
     static HashMap<CType,JType> arrayTypeMapping = new HashMap<CType,JType>();
@@ -27,7 +28,10 @@
     typeMapping.put(new CType("GLubyte"), new JType("byte"));
     typeMapping.put(new CType("GLuint"), new JType("int"));
     typeMapping.put(new CType("void"), new JType("void"));
-    typeMapping.put(new CType("GLubyte", true, true), new JType("String"));
+    typeMapping.put(new CType("GLubyte", true, true), new JType("String", false, false));
+    typeMapping.put(new CType("char", false, true), new JType("byte"));
+    typeMapping.put(new CType("char", true, true), new JType("String", false, false));
+    typeMapping.put(new CType("int"), new JType("int"));
 
     // Untyped pointers map to untyped Buffers
     typeMapping.put(new CType("GLvoid", true, true),
@@ -42,6 +46,8 @@
     // Typed pointers map to typed Buffers
     typeMapping.put(new CType("GLboolean", false, true),
             new JType("java.nio.IntBuffer", true, false));
+    typeMapping.put(new CType("GLenum", false, true),
+            new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLfixed", false, true),
             new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLfixed", true, true),
@@ -54,6 +60,8 @@
             new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLint", true, true),
             new JType("java.nio.IntBuffer", true, false));
+    typeMapping.put(new CType("GLsizei", false, true),
+            new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLuint", false, true),
             new JType("java.nio.IntBuffer", true, false));
     typeMapping.put(new CType("GLuint", true, true),
@@ -62,8 +70,11 @@
             new JType("java.nio.ShortBuffer", true, false));
 
     // Typed pointers map to arrays + offsets
+    arrayTypeMapping.put(new CType("char", false, true),
+            new JType("byte", false, true));
     arrayTypeMapping.put(new CType("GLboolean", false, true),
                  new JType("boolean", false, true));
+    arrayTypeMapping.put(new CType("GLenum", false, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLfixed", true, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLfixed", false, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLfloat", false, true), new JType("float", false, true));
@@ -71,6 +82,8 @@
     arrayTypeMapping.put(new CType("GLint", false, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLint", true, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLshort", true, true), new JType("short", false, true));
+    arrayTypeMapping.put(new CType("GLsizei", false, true), new JType("int", false, true));
+    arrayTypeMapping.put(new CType("GLsizei", true, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLuint", false, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLuint", true, true), new JType("int", false, true));
     arrayTypeMapping.put(new CType("GLintptr"), new JType("int", false, true));
@@ -109,6 +122,10 @@
     return isClass;
     }
 
+    public boolean isString() {
+        return baseType.equals("String");
+    }
+
     public boolean isPrimitive() {
     return !isClass() && !isArray();
     }
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 2cdb244..4c1814a 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -37,6 +37,12 @@
             jniName += "L";
         } else if (baseType.equals("byte")) {
             jniName += "B";
+        } else if (baseType.equals("String")) {
+            jniName += "Ljava/lang/String;";
+        } else if (baseType.equals("void")) {
+            // nothing.
+        } else {
+            throw new RuntimeException("Uknown primitive basetype " + baseType);
         }
         return jniName;
     }
@@ -629,7 +635,7 @@
         }
 
         // Append signature to function name
-        String sig = getJniMangledName(signature).replace('.', '_');
+        String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_');
         out.print("__" + sig);
         outName += "__" + sig;
 
@@ -652,6 +658,7 @@
         nativeRegistrations.add(s);
 
         List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
+        List<Integer> stringArgs = new ArrayList<Integer>();
         int numBufferArgs = 0;
         List<String> bufferArgNames = new ArrayList<String>();
 
@@ -682,6 +689,9 @@
             } else {
                 suffix = "";
             }
+            if (argType.isString()) {
+                stringArgs.add(new Integer(i));
+            }
 
             out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
         }
@@ -692,14 +702,19 @@
 
         int numArrays = 0;
         int numBuffers = 0;
+        int numStrings = 0;
         for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
             int idx = nonPrimitiveArgs.get(i).intValue();
-            if (jfunc.getArgType(idx).isArray()) {
+            JType argType = jfunc.getArgType(idx);
+            if (argType.isArray()) {
                 ++numArrays;
             }
-            if (jfunc.getArgType(idx).isBuffer()) {
+            if (argType.isBuffer()) {
                 ++numBuffers;
             }
+            if (argType.isString()) {
+                ++numStrings;
+            }
         }
 
         // Emit method body
@@ -736,7 +751,9 @@
                 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
         }
 
-        boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
+        boolean initializeReturnValue = stringArgs.size() > 0;
+
+        boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0 || numStrings > 0) &&
             hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
         // mChecker.getChecks(cfunc.getName()) != null
 
@@ -759,6 +776,9 @@
             if (retval != null) {
                 out.println(indent + returnType.getDeclaration() +
                             " _returnValue = " + retval + ";");
+            } else if (initializeReturnValue) {
+                out.println(indent + returnType.getDeclaration() +
+                " _returnValue = 0;");
             } else {
                 out.println(indent + returnType.getDeclaration() +
                             " _returnValue;");
@@ -789,7 +809,7 @@
                                 jfunc.getArgName(idx) +
                                 "_base = (" + decl + ") 0;");
                 }
-                remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
+                remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
                     "_" + cname + "Remaining";
                 out.println(indent +
                             "jint " + remaining + ";");
@@ -803,6 +823,40 @@
             out.println();
         }
 
+        // Emit local variable declaration for strings
+        if (stringArgs.size() > 0) {
+            for (int i = 0; i < stringArgs.size(); i++) {
+                int idx = stringArgs.get(i).intValue();
+                int cIndex = jfunc.getArgCIndex(idx);
+                String cname = cfunc.getArgName(cIndex);
+
+                out.println(indent + "const char* _native" + cname + " = 0;");
+            }
+
+            out.println();
+        }
+
+        // Null pointer checks and GetStringUTFChars
+        if (stringArgs.size() > 0) {
+            for (int i = 0; i < stringArgs.size(); i++) {
+                int idx = stringArgs.get(i).intValue();
+                int cIndex = jfunc.getArgCIndex(idx);
+                String cname = cfunc.getArgName(cIndex);
+
+                CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
+                String decl = type.getDeclaration();
+                out.println(indent + "if (!" + cname + ") {");
+                out.println(indent + "    _env->ThrowNew(IAEClass, \"" + cname + " == null\");");
+                out.println(indent + "    goto exit;");
+                needsExit = true;
+                out.println(indent + "}");
+
+                out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);");
+            }
+
+            out.println();
+        }
+
         // Emit 'GetPrimitiveArrayCritical' for arrays
         // Emit 'GetPointer' calls for Buffer pointers
         int bufArgIdx = 0;
@@ -814,7 +868,7 @@
                 String cname = cfunc.getArgName(cIndex);
                 offset = numArrays <= 1 ? "offset" :
                     cname + "Offset";
-                remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
+                remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
                     "_" + cname + "Remaining";
 
                 if (jfunc.getArgType(idx).isArray()) {
@@ -957,8 +1011,11 @@
                 out.print(indent + indent +
                           "(" +
                           typecast +
-                          ")" +
-                          cfunc.getArgName(i));
+                          ")");
+                if (cfunc.getArgType(i).isConstCharPointer()) {
+                    out.print("_native");
+                }
+                out.print(cfunc.getArgName(i));
 
                 if (i == numArgs - 1) {
                     if (isPointerFunc) {
@@ -1025,6 +1082,22 @@
             }
         }
 
+        // Emit local variable declaration for strings
+        if (stringArgs.size() > 0) {
+            for (int i = 0; i < stringArgs.size(); i++) {
+                int idx = stringArgs.get(i).intValue();
+                int cIndex = jfunc.getArgCIndex(idx);
+                String cname = cfunc.getArgName(cIndex);
+
+                out.println(indent + "if (_native" + cname + ") {");
+                out.println(indent + "    _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");");
+                out.println(indent + "}");
+            }
+
+            out.println();
+        }
+
+
         if (!isVoid) {
             out.println(indent + "return _returnValue;");
         }