Mega Code Archive

 
Categories / Android / 2D Graphics
 

OpenGL Sprite Text Activity

/*  * Copyright (C) 2008 The Android Open Source Project  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package com.example.android.apis.graphics.spritetext; import java.io.IOException; import java.io.InputStream; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.util.ArrayList; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL10Ext; import javax.microedition.khronos.opengles.GL11; import javax.microedition.khronos.opengles.GL11Ext; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.opengl.GLSurfaceView; import android.opengl.GLU; import android.opengl.GLUtils; import android.opengl.Matrix; import android.os.Bundle; import android.os.SystemClock; import android.util.Log; /**  * An OpenGL text label maker.  *   *   * OpenGL labels are implemented by creating a Bitmap, drawing all the labels  * into the Bitmap, converting the Bitmap into an Alpha texture, and drawing  * portions of the texture using glDrawTexiOES.  *   * The benefits of this approach are that the labels are drawn using the high  * quality anti-aliased font rasterizer, full character set support, and all the  * text labels are stored on a single texture, which makes it faster to use.  *   * The drawbacks are that you can only have as many labels as will fit onto one  * texture, and you have to recreate the whole texture if any label text  * changes.  *   */ class LabelMaker {   /**    * Create a label maker or maximum compatibility with various OpenGL ES    * implementations, the strike width and height must be powers of two, We    * want the strike width to be at least as wide as the widest window.    *     * @param fullColor    *            true if we want a full color backing store (4444), otherwise    *            we generate a grey L8 backing store.    * @param strikeWidth    *            width of strike    * @param strikeHeight    *            height of strike    */   public LabelMaker(boolean fullColor, int strikeWidth, int strikeHeight) {     mFullColor = fullColor;     mStrikeWidth = strikeWidth;     mStrikeHeight = strikeHeight;     mTexelWidth = (float) (1.0 / mStrikeWidth);     mTexelHeight = (float) (1.0 / mStrikeHeight);     mClearPaint = new Paint();     mClearPaint.setARGB(0, 0, 0, 0);     mClearPaint.setStyle(Style.FILL);     mState = STATE_NEW;   }   /**    * Call to initialize the class. Call whenever the surface has been created.    *     * @param gl    */   public void initialize(GL10 gl) {     mState = STATE_INITIALIZED;     int[] textures = new int[1];     gl.glGenTextures(1, textures, 0);     mTextureID = textures[0];     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);     // Use Nearest for performance.     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,         GL10.GL_NEAREST);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,         GL10.GL_NEAREST);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,         GL10.GL_CLAMP_TO_EDGE);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,         GL10.GL_CLAMP_TO_EDGE);     gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,         GL10.GL_REPLACE);   }   /**    * Call when the surface has been destroyed    */   public void shutdown(GL10 gl) {     if (gl != null) {       if (mState > STATE_NEW) {         int[] textures = new int[1];         textures[0] = mTextureID;         gl.glDeleteTextures(1, textures, 0);         mState = STATE_NEW;       }     }   }   /**    * Call before adding labels. Clears out any existing labels.    *     * @param gl    */   public void beginAdding(GL10 gl) {     checkState(STATE_INITIALIZED, STATE_ADDING);     mLabels.clear();     mU = 0;     mV = 0;     mLineHeight = 0;     Bitmap.Config config = mFullColor ? Bitmap.Config.ARGB_4444         : Bitmap.Config.ALPHA_8;     mBitmap = Bitmap.createBitmap(mStrikeWidth, mStrikeHeight, config);     mCanvas = new Canvas(mBitmap);     mBitmap.eraseColor(0);   }   /**    * Call to add a label    *     * @param gl    * @param text    *            the text of the label    * @param textPaint    *            the paint of the label    * @return the id of the label, used to measure and draw the label    */   public int add(GL10 gl, String text, Paint textPaint) {     return add(gl, null, text, textPaint);   }   /**    * Call to add a label    *     * @param gl    * @param text    *            the text of the label    * @param textPaint    *            the paint of the label    * @return the id of the label, used to measure and draw the label    */   public int add(GL10 gl, Drawable background, String text, Paint textPaint) {     return add(gl, background, text, textPaint, 0, 0);   }   /**    * Call to add a label    *     * @return the id of the label, used to measure and draw the label    */   public int add(GL10 gl, Drawable drawable, int minWidth, int minHeight) {     return add(gl, drawable, null, null, minWidth, minHeight);   }   /**    * Call to add a label    *     * @param gl    * @param text    *            the text of the label    * @param textPaint    *            the paint of the label    * @return the id of the label, used to measure and draw the label    */   public int add(GL10 gl, Drawable background, String text, Paint textPaint,       int minWidth, int minHeight) {     checkState(STATE_ADDING, STATE_ADDING);     boolean drawBackground = background != null;     boolean drawText = (text != null) && (textPaint != null);     Rect padding = new Rect();     if (drawBackground) {       background.getPadding(padding);       minWidth = Math.max(minWidth, background.getMinimumWidth());       minHeight = Math.max(minHeight, background.getMinimumHeight());     }     int ascent = 0;     int descent = 0;     int measuredTextWidth = 0;     if (drawText) {       // Paint.ascent is negative, so negate it.       ascent = (int) Math.ceil(-textPaint.ascent());       descent = (int) Math.ceil(textPaint.descent());       measuredTextWidth = (int) Math.ceil(textPaint.measureText(text));     }     int textHeight = ascent + descent;     int textWidth = Math.min(mStrikeWidth, measuredTextWidth);     int padHeight = padding.top + padding.bottom;     int padWidth = padding.left + padding.right;     int height = Math.max(minHeight, textHeight + padHeight);     int width = Math.max(minWidth, textWidth + padWidth);     int effectiveTextHeight = height - padHeight;     int effectiveTextWidth = width - padWidth;     int centerOffsetHeight = (effectiveTextHeight - textHeight) / 2;     int centerOffsetWidth = (effectiveTextWidth - textWidth) / 2;     // Make changes to the local variables, only commit them     // to the member variables after we've decided not to throw     // any exceptions.     int u = mU;     int v = mV;     int lineHeight = mLineHeight;     if (width > mStrikeWidth) {       width = mStrikeWidth;     }     // Is there room for this string on the current line?     if (u + width > mStrikeWidth) {       // No room, go to the next line:       u = 0;       v += lineHeight;       lineHeight = 0;     }     lineHeight = Math.max(lineHeight, height);     if (v + lineHeight > mStrikeHeight) {       throw new IllegalArgumentException("Out of texture space.");     }     int u2 = u + width;     int vBase = v + ascent;     int v2 = v + height;     if (drawBackground) {       background.setBounds(u, v, u + width, v + height);       background.draw(mCanvas);     }     if (drawText) {       mCanvas.drawText(text, u + padding.left + centerOffsetWidth, vBase           + padding.top + centerOffsetHeight, textPaint);     }     // We know there's enough space, so update the member variables     mU = u + width;     mV = v;     mLineHeight = lineHeight;     mLabels.add(new Label(width, height, ascent, u, v + height, width,         -height));     return mLabels.size() - 1;   }   /**    * Call to end adding labels. Must be called before drawing starts.    *     * @param gl    */   public void endAdding(GL10 gl) {     checkState(STATE_ADDING, STATE_INITIALIZED);     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);     // Reclaim storage used by bitmap and canvas.     mBitmap.recycle();     mBitmap = null;     mCanvas = null;   }   /**    * Get the width in pixels of a given label.    *     * @param labelID    * @return the width in pixels    */   public float getWidth(int labelID) {     return mLabels.get(labelID).width;   }   /**    * Get the height in pixels of a given label.    *     * @param labelID    * @return the height in pixels    */   public float getHeight(int labelID) {     return mLabels.get(labelID).height;   }   /**    * Get the baseline of a given label. That's how many pixels from the top of    * the label to the text baseline. (This is equivalent to the negative of    * the label's paint's ascent.)    *     * @param labelID    * @return the baseline in pixels.    */   public float getBaseline(int labelID) {     return mLabels.get(labelID).baseline;   }   /**    * Begin drawing labels. Sets the OpenGL state for rapid drawing.    *     * @param gl    * @param viewWidth    * @param viewHeight    */   public void beginDrawing(GL10 gl, float viewWidth, float viewHeight) {     checkState(STATE_INITIALIZED, STATE_DRAWING);     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);     gl.glShadeModel(GL10.GL_FLAT);     gl.glEnable(GL10.GL_BLEND);     gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);     gl.glColor4x(0x10000, 0x10000, 0x10000, 0x10000);     gl.glMatrixMode(GL10.GL_PROJECTION);     gl.glPushMatrix();     gl.glLoadIdentity();     gl.glOrthof(0.0f, viewWidth, 0.0f, viewHeight, 0.0f, 1.0f);     gl.glMatrixMode(GL10.GL_MODELVIEW);     gl.glPushMatrix();     gl.glLoadIdentity();     // Magic offsets to promote consistent rasterization.     gl.glTranslatef(0.375f, 0.375f, 0.0f);   }   /**    * Draw a given label at a given x,y position, expressed in pixels, with the    * lower-left-hand-corner of the view being (0,0).    *     * @param gl    * @param x    * @param y    * @param labelID    */   public void draw(GL10 gl, float x, float y, int labelID) {     checkState(STATE_DRAWING, STATE_DRAWING);     Label label = mLabels.get(labelID);     gl.glEnable(GL10.GL_TEXTURE_2D);     ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D,         GL11Ext.GL_TEXTURE_CROP_RECT_OES, label.mCrop, 0);     ((GL11Ext) gl).glDrawTexiOES((int) x, (int) y, 0, (int) label.width,         (int) label.height);   }   /**    * Ends the drawing and restores the OpenGL state.    *     * @param gl    */   public void endDrawing(GL10 gl) {     checkState(STATE_DRAWING, STATE_INITIALIZED);     gl.glDisable(GL10.GL_BLEND);     gl.glMatrixMode(GL10.GL_PROJECTION);     gl.glPopMatrix();     gl.glMatrixMode(GL10.GL_MODELVIEW);     gl.glPopMatrix();   }   private void checkState(int oldState, int newState) {     if (mState != oldState) {       throw new IllegalArgumentException("Can't call this method now.");     }     mState = newState;   }   private static class Label {     public Label(float width, float height, float baseLine, int cropU,         int cropV, int cropW, int cropH) {       this.width = width;       this.height = height;       this.baseline = baseLine;       int[] crop = new int[4];       crop[0] = cropU;       crop[1] = cropV;       crop[2] = cropW;       crop[3] = cropH;       mCrop = crop;     }     public float width;     public float height;     public float baseline;     public int[] mCrop;   }   private int mStrikeWidth;   private int mStrikeHeight;   private boolean mFullColor;   private Bitmap mBitmap;   private Canvas mCanvas;   private Paint mClearPaint;   private int mTextureID;   private float mTexelWidth; // Convert texel to U   private float mTexelHeight; // Convert texel to V   private int mU;   private int mV;   private int mLineHeight;   private ArrayList<Label> mLabels = new ArrayList<Label>();   private static final int STATE_NEW = 0;   private static final int STATE_INITIALIZED = 1;   private static final int STATE_ADDING = 2;   private static final int STATE_DRAWING = 3;   private int mState; } class SpriteTextRenderer implements GLSurfaceView.Renderer {   public SpriteTextRenderer(Context context) {     mContext = context;     mTriangle = new Triangle();     mProjector = new Projector();     mLabelPaint = new Paint();     mLabelPaint.setTextSize(32);     mLabelPaint.setAntiAlias(true);     mLabelPaint.setARGB(0xff, 0x00, 0x00, 0x00);   }   public void onSurfaceCreated(GL10 gl, EGLConfig config) {     /*      * By default, OpenGL enables features that improve quality but reduce      * performance. One might want to tweak that especially on software      * renderer.      */     gl.glDisable(GL10.GL_DITHER);     /*      * Some one-time OpenGL initialization can be made here probably based      * on features of this particular context      */     gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);     gl.glClearColor(.5f, .5f, .5f, 1);     gl.glShadeModel(GL10.GL_SMOOTH);     gl.glEnable(GL10.GL_DEPTH_TEST);     gl.glEnable(GL10.GL_TEXTURE_2D);     /*      * Create our texture. This has to be done each time the surface is      * created.      */     int[] textures = new int[1];     gl.glGenTextures(1, textures, 0);     mTextureID = textures[0];     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,         GL10.GL_NEAREST);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,         GL10.GL_LINEAR);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,         GL10.GL_CLAMP_TO_EDGE);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,         GL10.GL_CLAMP_TO_EDGE);     gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,         GL10.GL_REPLACE);     InputStream is = mContext.getResources().openRawResource(R.raw.robot);     Bitmap bitmap;     try {       bitmap = BitmapFactory.decodeStream(is);     } finally {       try {         is.close();       } catch (IOException e) {         // Ignore.       }     }     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);     bitmap.recycle();     if (mLabels != null) {       mLabels.shutdown(gl);     } else {       mLabels = new LabelMaker(true, 256, 64);     }     mLabels.initialize(gl);     mLabels.beginAdding(gl);     mLabelA = mLabels.add(gl, "A", mLabelPaint);     mLabelB = mLabels.add(gl, "B", mLabelPaint);     mLabelC = mLabels.add(gl, "C", mLabelPaint);     mLabelMsPF = mLabels.add(gl, "ms/f", mLabelPaint);     mLabels.endAdding(gl);     if (mNumericSprite != null) {       mNumericSprite.shutdown(gl);     } else {       mNumericSprite = new NumericSprite();     }     mNumericSprite.initialize(gl, mLabelPaint);   }   public void onDrawFrame(GL10 gl) {     /*      * By default, OpenGL enables features that improve quality but reduce      * performance. One might want to tweak that especially on software      * renderer.      */     gl.glDisable(GL10.GL_DITHER);     gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,         GL10.GL_MODULATE);     /*      * Usually, the first thing one might want to do is to clear the screen.      * The most efficient way of doing this is to use glClear().      */     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);     /*      * Now we're ready to draw some 3D objects      */     gl.glMatrixMode(GL10.GL_MODELVIEW);     gl.glLoadIdentity();     GLU.gluLookAt(gl, 0.0f, 0.0f, -2.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);     gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);     gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);     gl.glActiveTexture(GL10.GL_TEXTURE0);     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);     gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,         GL10.GL_REPEAT);     gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,         GL10.GL_REPEAT);     if (false) {       long time = SystemClock.uptimeMillis();       if (mLastTime != 0) {         long delta = time - mLastTime;         Log.w("time", Long.toString(delta));       }       mLastTime = time;     }     long time = SystemClock.uptimeMillis() % 4000L;     float angle = 0.090f * ((int) time);     gl.glRotatef(angle, 0, 0, 1.0f);     gl.glScalef(2.0f, 2.0f, 2.0f);     mTriangle.draw(gl);     mProjector.getCurrentModelView(gl);     mLabels.beginDrawing(gl, mWidth, mHeight);     drawLabel(gl, 0, mLabelA);     drawLabel(gl, 1, mLabelB);     drawLabel(gl, 2, mLabelC);     float msPFX = mWidth - mLabels.getWidth(mLabelMsPF) - 1;     mLabels.draw(gl, msPFX, 0, mLabelMsPF);     mLabels.endDrawing(gl);     drawMsPF(gl, msPFX);   }   private void drawMsPF(GL10 gl, float rightMargin) {     long time = SystemClock.uptimeMillis();     if (mStartTime == 0) {       mStartTime = time;     }     if (mFrames++ == SAMPLE_PERIOD_FRAMES) {       mFrames = 0;       long delta = time - mStartTime;       mStartTime = time;       mMsPerFrame = (int) (delta * SAMPLE_FACTOR);     }     if (mMsPerFrame > 0) {       mNumericSprite.setValue(mMsPerFrame);       float numWidth = mNumericSprite.width();       float x = rightMargin - numWidth;       mNumericSprite.draw(gl, x, 0, mWidth, mHeight);     }   }   private void drawLabel(GL10 gl, int triangleVertex, int labelId) {     float x = mTriangle.getX(triangleVertex);     float y = mTriangle.getY(triangleVertex);     mScratch[0] = x;     mScratch[1] = y;     mScratch[2] = 0.0f;     mScratch[3] = 1.0f;     mProjector.project(mScratch, 0, mScratch, 4);     float sx = mScratch[4];     float sy = mScratch[5];     float height = mLabels.getHeight(labelId);     float width = mLabels.getWidth(labelId);     float tx = sx - width * 0.5f;     float ty = sy - height * 0.5f;     mLabels.draw(gl, tx, ty, labelId);   }   public void onSurfaceChanged(GL10 gl, int w, int h) {     mWidth = w;     mHeight = h;     gl.glViewport(0, 0, w, h);     mProjector.setCurrentView(0, 0, w, h);     /*      * Set our projection matrix. This doesn't have to be done each time we      * draw, but usually a new projection needs to be set when the viewport      * is resized.      */     float ratio = (float) w / h;     gl.glMatrixMode(GL10.GL_PROJECTION);     gl.glLoadIdentity();     gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);     mProjector.getCurrentProjection(gl);   }   private int mWidth;   private int mHeight;   private Context mContext;   private Triangle mTriangle;   private int mTextureID;   private int mFrames;   private int mMsPerFrame;   private final static int SAMPLE_PERIOD_FRAMES = 12;   private final static float SAMPLE_FACTOR = 1.0f / SAMPLE_PERIOD_FRAMES;   private long mStartTime;   private LabelMaker mLabels;   private Paint mLabelPaint;   private int mLabelA;   private int mLabelB;   private int mLabelC;   private int mLabelMsPF;   private Projector mProjector;   private NumericSprite mNumericSprite;   private float[] mScratch = new float[8];   private long mLastTime; } class Triangle {   public Triangle() {     // Buffers to be passed to gl*Pointer() functions     // must be direct, i.e., they must be placed on the     // native heap where the garbage collector cannot     // move them.     //     // Buffers with multi-byte datatypes (e.g., short, int, float)     // must have their byte order set to native order     ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);     vbb.order(ByteOrder.nativeOrder());     mFVertexBuffer = vbb.asFloatBuffer();     ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4);     tbb.order(ByteOrder.nativeOrder());     mTexBuffer = tbb.asFloatBuffer();     ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);     ibb.order(ByteOrder.nativeOrder());     mIndexBuffer = ibb.asShortBuffer();     for (int i = 0; i < VERTS; i++) {       for (int j = 0; j < 3; j++) {         mFVertexBuffer.put(sCoords[i * 3 + j]);       }     }     for (int i = 0; i < VERTS; i++) {       for (int j = 0; j < 2; j++) {         mTexBuffer.put(sCoords[i * 3 + j] * 2.0f + 0.5f);       }     }     for (int i = 0; i < VERTS; i++) {       mIndexBuffer.put((short) i);     }     mFVertexBuffer.position(0);     mTexBuffer.position(0);     mIndexBuffer.position(0);   }   public void draw(GL10 gl) {     gl.glFrontFace(GL10.GL_CCW);     gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);     gl.glEnable(GL10.GL_TEXTURE_2D);     gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexBuffer);     gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, VERTS,         GL10.GL_UNSIGNED_SHORT, mIndexBuffer);   }   public float getX(int vertex) {     return sCoords[3 * vertex];   }   public float getY(int vertex) {     return sCoords[3 * vertex + 1];   }   private final static int VERTS = 3;   private FloatBuffer mFVertexBuffer;   private FloatBuffer mTexBuffer;   private ShortBuffer mIndexBuffer;   // A unit-sided equalateral triangle centered on the origin.   private final static float[] sCoords = {       // X, Y, Z       -0.5f, -0.25f, 0, 0.5f, -0.25f, 0, 0.0f, 0.559016994f, 0 }; } /**  * A utility that projects  *   */ class Projector {   public Projector() {     mMVP = new float[16];     mV = new float[4];     mGrabber = new MatrixGrabber();   }   public void setCurrentView(int x, int y, int width, int height) {     mX = x;     mY = y;     mViewWidth = width;     mViewHeight = height;   }   public void project(float[] obj, int objOffset, float[] win, int winOffset) {     if (!mMVPComputed) {       Matrix.multiplyMM(mMVP, 0, mGrabber.mProjection, 0,           mGrabber.mModelView, 0);       mMVPComputed = true;     }     Matrix.multiplyMV(mV, 0, mMVP, 0, obj, objOffset);     float rw = 1.0f / mV[3];     win[winOffset] = mX + mViewWidth * (mV[0] * rw + 1.0f) * 0.5f;     win[winOffset + 1] = mY + mViewHeight * (mV[1] * rw + 1.0f) * 0.5f;     win[winOffset + 2] = (mV[2] * rw + 1.0f) * 0.5f;   }   /**    * Get the current projection matrix. Has the side-effect of setting current    * matrix mode to GL_PROJECTION    *     * @param gl    */   public void getCurrentProjection(GL10 gl) {     mGrabber.getCurrentProjection(gl);     mMVPComputed = false;   }   /**    * Get the current model view matrix. Has the side-effect of setting current    * matrix mode to GL_MODELVIEW    *     * @param gl    */   public void getCurrentModelView(GL10 gl) {     mGrabber.getCurrentModelView(gl);     mMVPComputed = false;   }   private MatrixGrabber mGrabber;   private boolean mMVPComputed;   private float[] mMVP;   private float[] mV;   private int mX;   private int mY;   private int mViewWidth;   private int mViewHeight; } /**  * Allows retrieving the current matrix even if the current OpenGL ES driver  * does not support retrieving the current matrix.  *   * Note: the actual matrix may differ from the retrieved matrix, due to  * differences in the way the math is implemented by GLMatrixWrapper as compared  * to the way the math is implemented by the OpenGL ES driver.  */ class MatrixTrackingGL implements GL, GL10, GL10Ext, GL11, GL11Ext {   private GL10 mgl;   private GL10Ext mgl10Ext;   private GL11 mgl11;   private GL11Ext mgl11Ext;   private int mMatrixMode;   private MatrixStack mCurrent;   private MatrixStack mModelView;   private MatrixStack mTexture;   private MatrixStack mProjection;   private final static boolean _check = false;   ByteBuffer mByteBuffer;   FloatBuffer mFloatBuffer;   float[] mCheckA;   float[] mCheckB;   public MatrixTrackingGL(GL gl) {     mgl = (GL10) gl;     if (gl instanceof GL10Ext) {       mgl10Ext = (GL10Ext) gl;     }     if (gl instanceof GL11) {       mgl11 = (GL11) gl;     }     if (gl instanceof GL11Ext) {       mgl11Ext = (GL11Ext) gl;     }     mModelView = new MatrixStack();     mProjection = new MatrixStack();     mTexture = new MatrixStack();     mCurrent = mModelView;     mMatrixMode = GL10.GL_MODELVIEW;   }   // ---------------------------------------------------------------------   // GL10 methods:   public void glActiveTexture(int texture) {     mgl.glActiveTexture(texture);   }   public void glAlphaFunc(int func, float ref) {     mgl.glAlphaFunc(func, ref);   }   public void glAlphaFuncx(int func, int ref) {     mgl.glAlphaFuncx(func, ref);   }   public void glBindTexture(int target, int texture) {     mgl.glBindTexture(target, texture);   }   public void glBlendFunc(int sfactor, int dfactor) {     mgl.glBlendFunc(sfactor, dfactor);   }   public void glClear(int mask) {     mgl.glClear(mask);   }   public void glClearColor(float red, float green, float blue, float alpha) {     mgl.glClearColor(red, green, blue, alpha);   }   public void glClearColorx(int red, int green, int blue, int alpha) {     mgl.glClearColorx(red, green, blue, alpha);   }   public void glClearDepthf(float depth) {     mgl.glClearDepthf(depth);   }   public void glClearDepthx(int depth) {     mgl.glClearDepthx(depth);   }   public void glClearStencil(int s) {     mgl.glClearStencil(s);   }   public void glClientActiveTexture(int texture) {     mgl.glClientActiveTexture(texture);   }   public void glColor4f(float red, float green, float blue, float alpha) {     mgl.glColor4f(red, green, blue, alpha);   }   public void glColor4x(int red, int green, int blue, int alpha) {     mgl.glColor4x(red, green, blue, alpha);   }   public void glColorMask(boolean red, boolean green, boolean blue,       boolean alpha) {     mgl.glColorMask(red, green, blue, alpha);   }   public void glColorPointer(int size, int type, int stride, Buffer pointer) {     mgl.glColorPointer(size, type, stride, pointer);   }   public void glCompressedTexImage2D(int target, int level,       int internalformat, int width, int height, int border,       int imageSize, Buffer data) {     mgl.glCompressedTexImage2D(target, level, internalformat, width,         height, border, imageSize, data);   }   public void glCompressedTexSubImage2D(int target, int level, int xoffset,       int yoffset, int width, int height, int format, int imageSize,       Buffer data) {     mgl.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width,         height, format, imageSize, data);   }   public void glCopyTexImage2D(int target, int level, int internalformat,       int x, int y, int width, int height, int border) {     mgl.glCopyTexImage2D(target, level, internalformat, x, y, width,         height, border);   }   public void glCopyTexSubImage2D(int target, int level, int xoffset,       int yoffset, int x, int y, int width, int height) {     mgl.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width,         height);   }   public void glCullFace(int mode) {     mgl.glCullFace(mode);   }   public void glDeleteTextures(int n, int[] textures, int offset) {     mgl.glDeleteTextures(n, textures, offset);   }   public void glDeleteTextures(int n, IntBuffer textures) {     mgl.glDeleteTextures(n, textures);   }   public void glDepthFunc(int func) {     mgl.glDepthFunc(func);   }   public void glDepthMask(boolean flag) {     mgl.glDepthMask(flag);   }   public void glDepthRangef(float near, float far) {     mgl.glDepthRangef(near, far);   }   public void glDepthRangex(int near, int far) {     mgl.glDepthRangex(near, far);   }   public void glDisable(int cap) {     mgl.glDisable(cap);   }   public void glDisableClientState(int array) {     mgl.glDisableClientState(array);   }   public void glDrawArrays(int mode, int first, int count) {     mgl.glDrawArrays(mode, first, count);   }   public void glDrawElements(int mode, int count, int type, Buffer indices) {     mgl.glDrawElements(mode, count, type, indices);   }   public void glEnable(int cap) {     mgl.glEnable(cap);   }   public void glEnableClientState(int array) {     mgl.glEnableClientState(array);   }   public void glFinish() {     mgl.glFinish();   }   public void glFlush() {     mgl.glFlush();   }   public void glFogf(int pname, float param) {     mgl.glFogf(pname, param);   }   public void glFogfv(int pname, float[] params, int offset) {     mgl.glFogfv(pname, params, offset);   }   public void glFogfv(int pname, FloatBuffer params) {     mgl.glFogfv(pname, params);   }   public void glFogx(int pname, int param) {     mgl.glFogx(pname, param);   }   public void glFogxv(int pname, int[] params, int offset) {     mgl.glFogxv(pname, params, offset);   }   public void glFogxv(int pname, IntBuffer params) {     mgl.glFogxv(pname, params);   }   public void glFrontFace(int mode) {     mgl.glFrontFace(mode);   }   public void glFrustumf(float left, float right, float bottom, float top,       float near, float far) {     mCurrent.glFrustumf(left, right, bottom, top, near, far);     mgl.glFrustumf(left, right, bottom, top, near, far);     if (_check)       check();   }   public void glFrustumx(int left, int right, int bottom, int top, int near,       int far) {     mCurrent.glFrustumx(left, right, bottom, top, near, far);     mgl.glFrustumx(left, right, bottom, top, near, far);     if (_check)       check();   }   public void glGenTextures(int n, int[] textures, int offset) {     mgl.glGenTextures(n, textures, offset);   }   public void glGenTextures(int n, IntBuffer textures) {     mgl.glGenTextures(n, textures);   }   public int glGetError() {     int result = mgl.glGetError();     return result;   }   public void glGetIntegerv(int pname, int[] params, int offset) {     mgl.glGetIntegerv(pname, params, offset);   }   public void glGetIntegerv(int pname, IntBuffer params) {     mgl.glGetIntegerv(pname, params);   }   public String glGetString(int name) {     String result = mgl.glGetString(name);     return result;   }   public void glHint(int target, int mode) {     mgl.glHint(target, mode);   }   public void glLightModelf(int pname, float param) {     mgl.glLightModelf(pname, param);   }   public void glLightModelfv(int pname, float[] params, int offset) {     mgl.glLightModelfv(pname, params, offset);   }   public void glLightModelfv(int pname, FloatBuffer params) {     mgl.glLightModelfv(pname, params);   }   public void glLightModelx(int pname, int param) {     mgl.glLightModelx(pname, param);   }   public void glLightModelxv(int pname, int[] params, int offset) {     mgl.glLightModelxv(pname, params, offset);   }   public void glLightModelxv(int pname, IntBuffer params) {     mgl.glLightModelxv(pname, params);   }   public void glLightf(int light, int pname, float param) {     mgl.glLightf(light, pname, param);   }   public void glLightfv(int light, int pname, float[] params, int offset) {     mgl.glLightfv(light, pname, params, offset);   }   public void glLightfv(int light, int pname, FloatBuffer params) {     mgl.glLightfv(light, pname, params);   }   public void glLightx(int light, int pname, int param) {     mgl.glLightx(light, pname, param);   }   public void glLightxv(int light, int pname, int[] params, int offset) {     mgl.glLightxv(light, pname, params, offset);   }   public void glLightxv(int light, int pname, IntBuffer params) {     mgl.glLightxv(light, pname, params);   }   public void glLineWidth(float width) {     mgl.glLineWidth(width);   }   public void glLineWidthx(int width) {     mgl.glLineWidthx(width);   }   public void glLoadIdentity() {     mCurrent.glLoadIdentity();     mgl.glLoadIdentity();     if (_check)       check();   }   public void glLoadMatrixf(float[] m, int offset) {     mCurrent.glLoadMatrixf(m, offset);     mgl.glLoadMatrixf(m, offset);     if (_check)       check();   }   public void glLoadMatrixf(FloatBuffer m) {     int position = m.position();     mCurrent.glLoadMatrixf(m);     m.position(position);     mgl.glLoadMatrixf(m);     if (_check)       check();   }   public void glLoadMatrixx(int[] m, int offset) {     mCurrent.glLoadMatrixx(m, offset);     mgl.glLoadMatrixx(m, offset);     if (_check)       check();   }   public void glLoadMatrixx(IntBuffer m) {     int position = m.position();     mCurrent.glLoadMatrixx(m);     m.position(position);     mgl.glLoadMatrixx(m);     if (_check)       check();   }   public void glLogicOp(int opcode) {     mgl.glLogicOp(opcode);   }   public void glMaterialf(int face, int pname, float param) {     mgl.glMaterialf(face, pname, param);   }   public void glMaterialfv(int face, int pname, float[] params, int offset) {     mgl.glMaterialfv(face, pname, params, offset);   }   public void glMaterialfv(int face, int pname, FloatBuffer params) {     mgl.glMaterialfv(face, pname, params);   }   public void glMaterialx(int face, int pname, int param) {     mgl.glMaterialx(face, pname, param);   }   public void glMaterialxv(int face, int pname, int[] params, int offset) {     mgl.glMaterialxv(face, pname, params, offset);   }   public void glMaterialxv(int face, int pname, IntBuffer params) {     mgl.glMaterialxv(face, pname, params);   }   public void glMatrixMode(int mode) {     switch (mode) {     case GL10.GL_MODELVIEW:       mCurrent = mModelView;       break;     case GL10.GL_TEXTURE:       mCurrent = mTexture;       break;     case GL10.GL_PROJECTION:       mCurrent = mProjection;       break;     default:       throw new IllegalArgumentException("Unknown matrix mode: " + mode);     }     mgl.glMatrixMode(mode);     mMatrixMode = mode;     if (_check)       check();   }   public void glMultMatrixf(float[] m, int offset) {     mCurrent.glMultMatrixf(m, offset);     mgl.glMultMatrixf(m, offset);     if (_check)       check();   }   public void glMultMatrixf(FloatBuffer m) {     int position = m.position();     mCurrent.glMultMatrixf(m);     m.position(position);     mgl.glMultMatrixf(m);     if (_check)       check();   }   public void glMultMatrixx(int[] m, int offset) {     mCurrent.glMultMatrixx(m, offset);     mgl.glMultMatrixx(m, offset);     if (_check)       check();   }   public void glMultMatrixx(IntBuffer m) {     int position = m.position();     mCurrent.glMultMatrixx(m);     m.position(position);     mgl.glMultMatrixx(m);     if (_check)       check();   }   public void glMultiTexCoord4f(int target, float s, float t, float r, float q) {     mgl.glMultiTexCoord4f(target, s, t, r, q);   }   public void glMultiTexCoord4x(int target, int s, int t, int r, int q) {     mgl.glMultiTexCoord4x(target, s, t, r, q);   }   public void glNormal3f(float nx, float ny, float nz) {     mgl.glNormal3f(nx, ny, nz);   }   public void glNormal3x(int nx, int ny, int nz) {     mgl.glNormal3x(nx, ny, nz);   }   public void glNormalPointer(int type, int stride, Buffer pointer) {     mgl.glNormalPointer(type, stride, pointer);   }   public void glOrthof(float left, float right, float bottom, float top,       float near, float far) {     mCurrent.glOrthof(left, right, bottom, top, near, far);     mgl.glOrthof(left, right, bottom, top, near, far);     if (_check)       check();   }   public void glOrthox(int left, int right, int bottom, int top, int near,       int far) {     mCurrent.glOrthox(left, right, bottom, top, near, far);     mgl.glOrthox(left, right, bottom, top, near, far);     if (_check)       check();   }   public void glPixelStorei(int pname, int param) {     mgl.glPixelStorei(pname, param);   }   public void glPointSize(float size) {     mgl.glPointSize(size);   }   public void glPointSizex(int size) {     mgl.glPointSizex(size);   }   public void glPolygonOffset(float factor, float units) {     mgl.glPolygonOffset(factor, units);   }   public void glPolygonOffsetx(int factor, int units) {     mgl.glPolygonOffsetx(factor, units);   }   public void glPopMatrix() {     mCurrent.glPopMatrix();     mgl.glPopMatrix();     if (_check)       check();   }   public void glPushMatrix() {     mCurrent.glPushMatrix();     mgl.glPushMatrix();     if (_check)       check();   }   public void glReadPixels(int x, int y, int width, int height, int format,       int type, Buffer pixels) {     mgl.glReadPixels(x, y, width, height, format, type, pixels);   }   public void glRotatef(float angle, float x, float y, float z) {     mCurrent.glRotatef(angle, x, y, z);     mgl.glRotatef(angle, x, y, z);     if (_check)       check();   }   public void glRotatex(int angle, int x, int y, int z) {     mCurrent.glRotatex(angle, x, y, z);     mgl.glRotatex(angle, x, y, z);     if (_check)       check();   }   public void glSampleCoverage(float value, boolean invert) {     mgl.glSampleCoverage(value, invert);   }   public void glSampleCoveragex(int value, boolean invert) {     mgl.glSampleCoveragex(value, invert);   }   public void glScalef(float x, float y, float z) {     mCurrent.glScalef(x, y, z);     mgl.glScalef(x, y, z);     if (_check)       check();   }   public void glScalex(int x, int y, int z) {     mCurrent.glScalex(x, y, z);     mgl.glScalex(x, y, z);     if (_check)       check();   }   public void glScissor(int x, int y, int width, int height) {     mgl.glScissor(x, y, width, height);   }   public void glShadeModel(int mode) {     mgl.glShadeModel(mode);   }   public void glStencilFunc(int func, int ref, int mask) {     mgl.glStencilFunc(func, ref, mask);   }   public void glStencilMask(int mask) {     mgl.glStencilMask(mask);   }   public void glStencilOp(int fail, int zfail, int zpass) {     mgl.glStencilOp(fail, zfail, zpass);   }   public void glTexCoordPointer(int size, int type, int stride, Buffer pointer) {     mgl.glTexCoordPointer(size, type, stride, pointer);   }   public void glTexEnvf(int target, int pname, float param) {     mgl.glTexEnvf(target, pname, param);   }   public void glTexEnvfv(int target, int pname, float[] params, int offset) {     mgl.glTexEnvfv(target, pname, params, offset);   }   public void glTexEnvfv(int target, int pname, FloatBuffer params) {     mgl.glTexEnvfv(target, pname, params);   }   public void glTexEnvx(int target, int pname, int param) {     mgl.glTexEnvx(target, pname, param);   }   public void glTexEnvxv(int target, int pname, int[] params, int offset) {     mgl.glTexEnvxv(target, pname, params, offset);   }   public void glTexEnvxv(int target, int pname, IntBuffer params) {     mgl.glTexEnvxv(target, pname, params);   }   public void glTexImage2D(int target, int level, int internalformat,       int width, int height, int border, int format, int type,       Buffer pixels) {     mgl.glTexImage2D(target, level, internalformat, width, height, border,         format, type, pixels);   }   public void glTexParameterf(int target, int pname, float param) {     mgl.glTexParameterf(target, pname, param);   }   public void glTexParameterx(int target, int pname, int param) {     mgl.glTexParameterx(target, pname, param);   }   public void glTexParameteriv(int target, int pname, int[] params, int offset) {     mgl11.glTexParameteriv(target, pname, params, offset);   }   public void glTexParameteriv(int target, int pname, IntBuffer params) {     mgl11.glTexParameteriv(target, pname, params);   }   public void glTexSubImage2D(int target, int level, int xoffset,       int yoffset, int width, int height, int format, int type,       Buffer pixels) {     mgl.glTexSubImage2D(target, level, xoffset, yoffset, width, height,         format, type, pixels);   }   public void glTranslatef(float x, float y, float z) {     mCurrent.glTranslatef(x, y, z);     mgl.glTranslatef(x, y, z);     if (_check)       check();   }   public void glTranslatex(int x, int y, int z) {     mCurrent.glTranslatex(x, y, z);     mgl.glTranslatex(x, y, z);     if (_check)       check();   }   public void glVertexPointer(int size, int type, int stride, Buffer pointer) {     mgl.glVertexPointer(size, type, stride, pointer);   }   public void glViewport(int x, int y, int width, int height) {     mgl.glViewport(x, y, width, height);   }   public void glClipPlanef(int plane, float[] equation, int offset) {     mgl11.glClipPlanef(plane, equation, offset);   }   public void glClipPlanef(int plane, FloatBuffer equation) {     mgl11.glClipPlanef(plane, equation);   }   public void glClipPlanex(int plane, int[] equation, int offset) {     mgl11.glClipPlanex(plane, equation, offset);   }   public void glClipPlanex(int plane, IntBuffer equation) {     mgl11.glClipPlanex(plane, equation);   }   // Draw Texture Extension   public void glDrawTexfOES(float x, float y, float z, float width,       float height) {     mgl11Ext.glDrawTexfOES(x, y, z, width, height);   }   public void glDrawTexfvOES(float[] coords, int offset) {     mgl11Ext.glDrawTexfvOES(coords, offset);   }   public void glDrawTexfvOES(FloatBuffer coords) {     mgl11Ext.glDrawTexfvOES(coords);   }   public void glDrawTexiOES(int x, int y, int z, int width, int height) {     mgl11Ext.glDrawTexiOES(x, y, z, width, height);   }   public void glDrawTexivOES(int[] coords, int offset) {     mgl11Ext.glDrawTexivOES(coords, offset);   }   public void glDrawTexivOES(IntBuffer coords) {     mgl11Ext.glDrawTexivOES(coords);   }   public void glDrawTexsOES(short x, short y, short z, short width,       short height) {     mgl11Ext.glDrawTexsOES(x, y, z, width, height);   }   public void glDrawTexsvOES(short[] coords, int offset) {     mgl11Ext.glDrawTexsvOES(coords, offset);   }   public void glDrawTexsvOES(ShortBuffer coords) {     mgl11Ext.glDrawTexsvOES(coords);   }   public void glDrawTexxOES(int x, int y, int z, int width, int height) {     mgl11Ext.glDrawTexxOES(x, y, z, width, height);   }   public void glDrawTexxvOES(int[] coords, int offset) {     mgl11Ext.glDrawTexxvOES(coords, offset);   }   public void glDrawTexxvOES(IntBuffer coords) {     mgl11Ext.glDrawTexxvOES(coords);   }   public int glQueryMatrixxOES(int[] mantissa, int mantissaOffset,       int[] exponent, int exponentOffset) {     return mgl10Ext.glQueryMatrixxOES(mantissa, mantissaOffset, exponent,         exponentOffset);   }   public int glQueryMatrixxOES(IntBuffer mantissa, IntBuffer exponent) {     return mgl10Ext.glQueryMatrixxOES(mantissa, exponent);   }   // Unsupported GL11 methods   public void glBindBuffer(int target, int buffer) {     throw new UnsupportedOperationException();   }   public void glBufferData(int target, int size, Buffer data, int usage) {     throw new UnsupportedOperationException();   }   public void glBufferSubData(int target, int offset, int size, Buffer data) {     throw new UnsupportedOperationException();   }   public void glColor4ub(byte red, byte green, byte blue, byte alpha) {     throw new UnsupportedOperationException();   }   public void glDeleteBuffers(int n, int[] buffers, int offset) {     throw new UnsupportedOperationException();   }   public void glDeleteBuffers(int n, IntBuffer buffers) {     throw new UnsupportedOperationException();   }   public void glGenBuffers(int n, int[] buffers, int offset) {     throw new UnsupportedOperationException();   }   public void glGenBuffers(int n, IntBuffer buffers) {     throw new UnsupportedOperationException();   }   public void glGetBooleanv(int pname, boolean[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glGetBooleanv(int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetBufferParameteriv(int target, int pname, int[] params,       int offset) {     throw new UnsupportedOperationException();   }   public void glGetBufferParameteriv(int target, int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetClipPlanef(int pname, float[] eqn, int offset) {     throw new UnsupportedOperationException();   }   public void glGetClipPlanef(int pname, FloatBuffer eqn) {     throw new UnsupportedOperationException();   }   public void glGetClipPlanex(int pname, int[] eqn, int offset) {     throw new UnsupportedOperationException();   }   public void glGetClipPlanex(int pname, IntBuffer eqn) {     throw new UnsupportedOperationException();   }   public void glGetFixedv(int pname, int[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glGetFixedv(int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetFloatv(int pname, float[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glGetFloatv(int pname, FloatBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetLightfv(int light, int pname, float[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glGetLightfv(int light, int pname, FloatBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetLightxv(int light, int pname, int[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glGetLightxv(int light, int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetMaterialfv(int face, int pname, float[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glGetMaterialfv(int face, int pname, FloatBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetMaterialxv(int face, int pname, int[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glGetMaterialxv(int face, int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetTexEnviv(int env, int pname, int[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glGetTexEnviv(int env, int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetTexEnvxv(int env, int pname, int[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glGetTexEnvxv(int env, int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetTexParameterfv(int target, int pname, float[] params,       int offset) {     throw new UnsupportedOperationException();   }   public void glGetTexParameterfv(int target, int pname, FloatBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetTexParameteriv(int target, int pname, int[] params,       int offset) {     throw new UnsupportedOperationException();   }   public void glGetTexParameteriv(int target, int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glGetTexParameterxv(int target, int pname, int[] params,       int offset) {     throw new UnsupportedOperationException();   }   public void glGetTexParameterxv(int target, int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public boolean glIsBuffer(int buffer) {     throw new UnsupportedOperationException();   }   public boolean glIsEnabled(int cap) {     throw new UnsupportedOperationException();   }   public boolean glIsTexture(int texture) {     throw new UnsupportedOperationException();   }   public void glPointParameterf(int pname, float param) {     throw new UnsupportedOperationException();   }   public void glPointParameterfv(int pname, float[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glPointParameterfv(int pname, FloatBuffer params) {     throw new UnsupportedOperationException();   }   public void glPointParameterx(int pname, int param) {     throw new UnsupportedOperationException();   }   public void glPointParameterxv(int pname, int[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glPointParameterxv(int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glPointSizePointerOES(int type, int stride, Buffer pointer) {     throw new UnsupportedOperationException();   }   public void glTexEnvi(int target, int pname, int param) {     throw new UnsupportedOperationException();   }   public void glTexEnviv(int target, int pname, int[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glTexEnviv(int target, int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glTexParameterfv(int target, int pname, float[] params,       int offset) {     throw new UnsupportedOperationException();   }   public void glTexParameterfv(int target, int pname, FloatBuffer params) {     throw new UnsupportedOperationException();   }   public void glTexParameteri(int target, int pname, int param) {     throw new UnsupportedOperationException();   }   public void glTexParameterxv(int target, int pname, int[] params, int offset) {     throw new UnsupportedOperationException();   }   public void glTexParameterxv(int target, int pname, IntBuffer params) {     throw new UnsupportedOperationException();   }   public void glColorPointer(int size, int type, int stride, int offset) {     throw new UnsupportedOperationException();   }   public void glDrawElements(int mode, int count, int type, int offset) {     throw new UnsupportedOperationException();   }   public void glGetPointerv(int pname, Buffer[] params) {     throw new UnsupportedOperationException();   }   public void glNormalPointer(int type, int stride, int offset) {     throw new UnsupportedOperationException();   }   public void glTexCoordPointer(int size, int type, int stride, int offset) {     throw new UnsupportedOperationException();   }   public void glVertexPointer(int size, int type, int stride, int offset) {     throw new UnsupportedOperationException();   }   public void glCurrentPaletteMatrixOES(int matrixpaletteindex) {     throw new UnsupportedOperationException();   }   public void glLoadPaletteFromModelViewMatrixOES() {     throw new UnsupportedOperationException();   }   public void glMatrixIndexPointerOES(int size, int type, int stride,       Buffer pointer) {     throw new UnsupportedOperationException();   }   public void glMatrixIndexPointerOES(int size, int type, int stride,       int offset) {     throw new UnsupportedOperationException();   }   public void glWeightPointerOES(int size, int type, int stride,       Buffer pointer) {     throw new UnsupportedOperationException();   }   public void glWeightPointerOES(int size, int type, int stride, int offset) {     throw new UnsupportedOperationException();   }   /**    * Get the current matrix    */   public void getMatrix(float[] m, int offset) {     mCurrent.getMatrix(m, offset);   }   /**    * Get the current matrix mode    */   public int getMatrixMode() {     return mMatrixMode;   }   private void check() {     int oesMode;     switch (mMatrixMode) {     case GL_MODELVIEW:       oesMode = GL11.GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES;       break;     case GL_PROJECTION:       oesMode = GL11.GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES;       break;     case GL_TEXTURE:       oesMode = GL11.GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES;       break;     default:       throw new IllegalArgumentException("Unknown matrix mode");     }     if (mByteBuffer == null) {       mCheckA = new float[16];       mCheckB = new float[16];       mByteBuffer = ByteBuffer.allocateDirect(64);       mByteBuffer.order(ByteOrder.nativeOrder());       mFloatBuffer = mByteBuffer.asFloatBuffer();     }     mgl.glGetIntegerv(oesMode, mByteBuffer.asIntBuffer());     for (int i = 0; i < 16; i++) {       mCheckB[i] = mFloatBuffer.get(i);     }     mCurrent.getMatrix(mCheckA, 0);     boolean fail = false;     for (int i = 0; i < 16; i++) {       if (mCheckA[i] != mCheckB[i]) {         Log.d("GLMatWrap", "i:" + i + " a:" + mCheckA[i] + " a:"             + mCheckB[i]);         fail = true;       }     }     if (fail) {       throw new IllegalArgumentException("Matrix math difference.");     }   } } /**  * A 2D rectangular mesh. Can be drawn textured or untextured.  *   */ class Grid {   public Grid(int w, int h) {     if (w < 0 || w >= 65536) {       throw new IllegalArgumentException("w");     }     if (h < 0 || h >= 65536) {       throw new IllegalArgumentException("h");     }     if (w * h >= 65536) {       throw new IllegalArgumentException("w * h >= 65536");     }     mW = w;     mH = h;     int size = w * h;     final int FLOAT_SIZE = 4;     final int CHAR_SIZE = 2;     mVertexBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 3)         .order(ByteOrder.nativeOrder()).asFloatBuffer();     mTexCoordBuffer = ByteBuffer.allocateDirect(FLOAT_SIZE * size * 2)         .order(ByteOrder.nativeOrder()).asFloatBuffer();     int quadW = mW - 1;     int quadH = mH - 1;     int quadCount = quadW * quadH;     int indexCount = quadCount * 6;     mIndexCount = indexCount;     mIndexBuffer = ByteBuffer.allocateDirect(CHAR_SIZE * indexCount)         .order(ByteOrder.nativeOrder()).asCharBuffer();     /*      * Initialize triangle list mesh.      *       * [0]-----[ 1] ... | / | | / | | / | [w]-----[w+1] ... | |      */     {       int i = 0;       for (int y = 0; y < quadH; y++) {         for (int x = 0; x < quadW; x++) {           char a = (char) (y * mW + x);           char b = (char) (y * mW + x + 1);           char c = (char) ((y + 1) * mW + x);           char d = (char) ((y + 1) * mW + x + 1);           mIndexBuffer.put(i++, a);           mIndexBuffer.put(i++, b);           mIndexBuffer.put(i++, c);           mIndexBuffer.put(i++, b);           mIndexBuffer.put(i++, c);           mIndexBuffer.put(i++, d);         }       }     }   }   void set(int i, int j, float x, float y, float z, float u, float v) {     if (i < 0 || i >= mW) {       throw new IllegalArgumentException("i");     }     if (j < 0 || j >= mH) {       throw new IllegalArgumentException("j");     }     int index = mW * j + i;     int posIndex = index * 3;     mVertexBuffer.put(posIndex, x);     mVertexBuffer.put(posIndex + 1, y);     mVertexBuffer.put(posIndex + 2, z);     int texIndex = index * 2;     mTexCoordBuffer.put(texIndex, u);     mTexCoordBuffer.put(texIndex + 1, v);   }   public void draw(GL10 gl, boolean useTexture) {     gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);     gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);     if (useTexture) {       gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);       gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexCoordBuffer);       gl.glEnable(GL10.GL_TEXTURE_2D);     } else {       gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);       gl.glDisable(GL10.GL_TEXTURE_2D);     }     gl.glDrawElements(GL10.GL_TRIANGLES, mIndexCount,         GL10.GL_UNSIGNED_SHORT, mIndexBuffer);     gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);   }   private FloatBuffer mVertexBuffer;   private FloatBuffer mTexCoordBuffer;   private CharBuffer mIndexBuffer;   private int mW;   private int mH;   private int mIndexCount; } class MatrixGrabber {   public MatrixGrabber() {     mModelView = new float[16];     mProjection = new float[16];   }   /**    * Record the current modelView and projection matrix state. Has the side    * effect of setting the current matrix state to GL_MODELVIEW    *     * @param gl    */   public void getCurrentState(GL10 gl) {     getCurrentProjection(gl);     getCurrentModelView(gl);   }   /**    * Record the current modelView matrix state. Has the side effect of setting    * the current matrix state to GL_MODELVIEW    *     * @param gl    */   public void getCurrentModelView(GL10 gl) {     getMatrix(gl, GL10.GL_MODELVIEW, mModelView);   }   /**    * Record the current projection matrix state. Has the side effect of    * setting the current matrix state to GL_PROJECTION    *     * @param gl    */   public void getCurrentProjection(GL10 gl) {     getMatrix(gl, GL10.GL_PROJECTION, mProjection);   }   private void getMatrix(GL10 gl, int mode, float[] mat) {     MatrixTrackingGL gl2 = (MatrixTrackingGL) gl;     gl2.glMatrixMode(mode);     gl2.getMatrix(mat, 0);   }   public float[] mModelView;   public float[] mProjection; } /**  * A matrix stack, similar to OpenGL ES's internal matrix stack.  */ class MatrixStack {   public MatrixStack() {     commonInit(DEFAULT_MAX_DEPTH);   }   public MatrixStack(int maxDepth) {     commonInit(maxDepth);   }   private void commonInit(int maxDepth) {     mMatrix = new float[maxDepth * MATRIX_SIZE];     mTemp = new float[MATRIX_SIZE * 2];     glLoadIdentity();   }   public void glFrustumf(float left, float right, float bottom, float top,       float near, float far) {     Matrix.frustumM(mMatrix, mTop, left, right, bottom, top, near, far);   }   public void glFrustumx(int left, int right, int bottom, int top, int near,       int far) {     glFrustumf(fixedToFloat(left), fixedToFloat(right),         fixedToFloat(bottom), fixedToFloat(top), fixedToFloat(near),         fixedToFloat(far));   }   public void glLoadIdentity() {     Matrix.setIdentityM(mMatrix, mTop);   }   public void glLoadMatrixf(float[] m, int offset) {     System.arraycopy(m, offset, mMatrix, mTop, MATRIX_SIZE);   }   public void glLoadMatrixf(FloatBuffer m) {     m.get(mMatrix, mTop, MATRIX_SIZE);   }   public void glLoadMatrixx(int[] m, int offset) {     for (int i = 0; i < MATRIX_SIZE; i++) {       mMatrix[mTop + i] = fixedToFloat(m[offset + i]);     }   }   public void glLoadMatrixx(IntBuffer m) {     for (int i = 0; i < MATRIX_SIZE; i++) {       mMatrix[mTop + i] = fixedToFloat(m.get());     }   }   public void glMultMatrixf(float[] m, int offset) {     System.arraycopy(mMatrix, mTop, mTemp, 0, MATRIX_SIZE);     Matrix.multiplyMM(mMatrix, mTop, mTemp, 0, m, offset);   }   public void glMultMatrixf(FloatBuffer m) {     m.get(mTemp, MATRIX_SIZE, MATRIX_SIZE);     glMultMatrixf(mTemp, MATRIX_SIZE);   }   public void glMultMatrixx(int[] m, int offset) {     for (int i = 0; i < MATRIX_SIZE; i++) {       mTemp[MATRIX_SIZE + i] = fixedToFloat(m[offset + i]);     }     glMultMatrixf(mTemp, MATRIX_SIZE);   }   public void glMultMatrixx(IntBuffer m) {     for (int i = 0; i < MATRIX_SIZE; i++) {       mTemp[MATRIX_SIZE + i] = fixedToFloat(m.get());     }     glMultMatrixf(mTemp, MATRIX_SIZE);   }   public void glOrthof(float left, float right, float bottom, float top,       float near, float far) {     Matrix.orthoM(mMatrix, mTop, left, right, bottom, top, near, far);   }   public void glOrthox(int left, int right, int bottom, int top, int near,       int far) {     glOrthof(fixedToFloat(left), fixedToFloat(right), fixedToFloat(bottom),         fixedToFloat(top), fixedToFloat(near), fixedToFloat(far));   }   public void glPopMatrix() {     preflight_adjust(-1);     adjust(-1);   }   public void glPushMatrix() {     preflight_adjust(1);     System.arraycopy(mMatrix, mTop, mMatrix, mTop + MATRIX_SIZE,         MATRIX_SIZE);     adjust(1);   }   public void glRotatef(float angle, float x, float y, float z) {     Matrix.setRotateM(mTemp, 0, angle, x, y, z);     System.arraycopy(mMatrix, mTop, mTemp, MATRIX_SIZE, MATRIX_SIZE);     Matrix.multiplyMM(mMatrix, mTop, mTemp, MATRIX_SIZE, mTemp, 0);   }   public void glRotatex(int angle, int x, int y, int z) {     glRotatef(angle, fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));   }   public void glScalef(float x, float y, float z) {     Matrix.scaleM(mMatrix, mTop, x, y, z);   }   public void glScalex(int x, int y, int z) {     glScalef(fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));   }   public void glTranslatef(float x, float y, float z) {     Matrix.translateM(mMatrix, mTop, x, y, z);   }   public void glTranslatex(int x, int y, int z) {     glTranslatef(fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));   }   public void getMatrix(float[] dest, int offset) {     System.arraycopy(mMatrix, mTop, dest, offset, MATRIX_SIZE);   }   private float fixedToFloat(int x) {     return x * (1.0f / 65536.0f);   }   private void preflight_adjust(int dir) {     int newTop = mTop + dir * MATRIX_SIZE;     if (newTop < 0) {       throw new IllegalArgumentException("stack underflow");     }     if (newTop + MATRIX_SIZE > mMatrix.length) {       throw new IllegalArgumentException("stack overflow");     }   }   private void adjust(int dir) {     mTop += dir * MATRIX_SIZE;   }   private final static int DEFAULT_MAX_DEPTH = 32;   private final static int MATRIX_SIZE = 16;   private float[] mMatrix;   private int mTop;   private float[] mTemp; } class NumericSprite {   public NumericSprite() {     mText = "";     mLabelMaker = null;   }   public void initialize(GL10 gl, Paint paint) {     int height = roundUpPower2((int) paint.getFontSpacing());     final float interDigitGaps = 9 * 1.0f;     int width = roundUpPower2((int) (interDigitGaps + paint         .measureText(sStrike)));     mLabelMaker = new LabelMaker(true, width, height);     mLabelMaker.initialize(gl);     mLabelMaker.beginAdding(gl);     for (int i = 0; i < 10; i++) {       String digit = sStrike.substring(i, i + 1);       mLabelId[i] = mLabelMaker.add(gl, digit, paint);       mWidth[i] = (int) Math.ceil(mLabelMaker.getWidth(i));     }     mLabelMaker.endAdding(gl);   }   public void shutdown(GL10 gl) {     mLabelMaker.shutdown(gl);     mLabelMaker = null;   }   /**    * Find the smallest power of two >= the input value. (Doesn't work for    * negative numbers.)    */   private int roundUpPower2(int x) {     x = x - 1;     x = x | (x >> 1);     x = x | (x >> 2);     x = x | (x >> 4);     x = x | (x >> 8);     x = x | (x >> 16);     return x + 1;   }   public void setValue(int value) {     mText = format(value);   }   public void draw(GL10 gl, float x, float y, float viewWidth,       float viewHeight) {     int length = mText.length();     mLabelMaker.beginDrawing(gl, viewWidth, viewHeight);     for (int i = 0; i < length; i++) {       char c = mText.charAt(i);       int digit = c - '0';       mLabelMaker.draw(gl, x, y, mLabelId[digit]);       x += mWidth[digit];     }     mLabelMaker.endDrawing(gl);   }   public float width() {     float width = 0.0f;     int length = mText.length();     for (int i = 0; i < length; i++) {       char c = mText.charAt(i);       width += mWidth[c - '0'];     }     return width;   }   private String format(int value) {     return Integer.toString(value);   }   private LabelMaker mLabelMaker;   private String mText;   private int[] mWidth = new int[10];   private int[] mLabelId = new int[10];   private final static String sStrike = "0123456789"; } public class SpriteTextActivity extends Activity {   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     mGLSurfaceView = new GLSurfaceView(this);     mGLSurfaceView.setGLWrapper(new GLSurfaceView.GLWrapper() {       public GL wrap(GL gl) {         return new MatrixTrackingGL(gl);       }     });     mGLSurfaceView.setRenderer(new SpriteTextRenderer(this));     setContentView(mGLSurfaceView);   }   @Override   protected void onPause() {     super.onPause();     mGLSurfaceView.onPause();   }   @Override   protected void onResume() {     super.onResume();     mGLSurfaceView.onResume();   }   private GLSurfaceView mGLSurfaceView; }