/* * 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 mLabels = new ArrayList(); 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; }