1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.apis.graphics.spritetext; 18 19 import java.io.IOException; 20 import java.io.InputStream; 21 import java.nio.ByteBuffer; 22 import java.nio.ByteOrder; 23 import java.nio.FloatBuffer; 24 import java.nio.ShortBuffer; 25 26 import javax.microedition.khronos.egl.EGL10; 27 import javax.microedition.khronos.egl.EGLConfig; 28 import javax.microedition.khronos.opengles.GL10; 29 30 import android.content.Context; 31 import android.graphics.Bitmap; 32 import android.graphics.BitmapFactory; 33 import android.graphics.Paint; 34 import android.opengl.GLSurfaceView; 35 import android.opengl.GLU; 36 import android.opengl.GLUtils; 37 import android.os.SystemClock; 38 39 import com.example.android.apis.R; 40 41 public class SpriteTextRenderer implements GLSurfaceView.Renderer{ 42 SpriteTextRenderer(Context context)43 public SpriteTextRenderer(Context context) { 44 mContext = context; 45 mTriangle = new Triangle(); 46 mProjector = new Projector(); 47 mLabelPaint = new Paint(); 48 mLabelPaint.setTextSize(32); 49 mLabelPaint.setAntiAlias(true); 50 mLabelPaint.setARGB(0xff, 0x00, 0x00, 0x00); 51 } 52 onSurfaceCreated(GL10 gl, EGLConfig config)53 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 54 /* 55 * By default, OpenGL enables features that improve quality 56 * but reduce performance. One might want to tweak that 57 * especially on software renderer. 58 */ 59 gl.glDisable(GL10.GL_DITHER); 60 61 /* 62 * Some one-time OpenGL initialization can be made here 63 * probably based on features of this particular context 64 */ 65 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, 66 GL10.GL_FASTEST); 67 68 gl.glClearColor(.5f, .5f, .5f, 1); 69 gl.glShadeModel(GL10.GL_SMOOTH); 70 gl.glEnable(GL10.GL_DEPTH_TEST); 71 gl.glEnable(GL10.GL_TEXTURE_2D); 72 73 /* 74 * Create our texture. This has to be done each time the 75 * surface is created. 76 */ 77 78 int[] textures = new int[1]; 79 gl.glGenTextures(1, textures, 0); 80 81 mTextureID = textures[0]; 82 gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID); 83 84 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, 85 GL10.GL_NEAREST); 86 gl.glTexParameterf(GL10.GL_TEXTURE_2D, 87 GL10.GL_TEXTURE_MAG_FILTER, 88 GL10.GL_LINEAR); 89 90 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, 91 GL10.GL_CLAMP_TO_EDGE); 92 gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, 93 GL10.GL_CLAMP_TO_EDGE); 94 95 gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, 96 GL10.GL_REPLACE); 97 98 InputStream is = mContext.getResources() 99 .openRawResource(R.drawable.robot); 100 Bitmap bitmap; 101 try { 102 bitmap = BitmapFactory.decodeStream(is); 103 } finally { 104 try { 105 is.close(); 106 } catch(IOException e) { 107 // Ignore. 108 } 109 } 110 111 GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); 112 bitmap.recycle(); 113 114 if (mLabels != null) { 115 mLabels.shutdown(gl); 116 } else { 117 mLabels = new LabelMaker(true, 256, 64); 118 } 119 mLabels.initialize(gl); 120 mLabels.beginAdding(gl); 121 mLabelA = mLabels.add(gl, "A", mLabelPaint); 122 mLabelB = mLabels.add(gl, "B", mLabelPaint); 123 mLabelC = mLabels.add(gl, "C", mLabelPaint); 124 mLabelMsPF = mLabels.add(gl, "ms/f", mLabelPaint); 125 mLabels.endAdding(gl); 126 127 if (mNumericSprite != null) { 128 mNumericSprite.shutdown(gl); 129 } else { 130 mNumericSprite = new NumericSprite(); 131 } 132 mNumericSprite.initialize(gl, mLabelPaint); 133 } 134 onDrawFrame(GL10 gl)135 public void onDrawFrame(GL10 gl) { 136 /* 137 * By default, OpenGL enables features that improve quality 138 * but reduce performance. One might want to tweak that 139 * especially on software renderer. 140 */ 141 gl.glDisable(GL10.GL_DITHER); 142 143 gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, 144 GL10.GL_MODULATE); 145 146 /* 147 * Usually, the first thing one might want to do is to clear 148 * the screen. The most efficient way of doing this is to use 149 * glClear(). 150 */ 151 152 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 153 154 /* 155 * Now we're ready to draw some 3D objects 156 */ 157 158 gl.glMatrixMode(GL10.GL_MODELVIEW); 159 gl.glLoadIdentity(); 160 161 GLU.gluLookAt(gl, 0.0f, 0.0f, -2.5f, 162 0.0f, 0.0f, 0.0f, 163 0.0f, 1.0f, 0.0f); 164 165 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 166 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 167 168 gl.glActiveTexture(GL10.GL_TEXTURE0); 169 gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID); 170 gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, 171 GL10.GL_REPEAT); 172 gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, 173 GL10.GL_REPEAT); 174 175 long time = SystemClock.uptimeMillis() % 4000L; 176 float angle = 0.090f * ((int) time); 177 178 gl.glRotatef(angle, 0, 0, 1.0f); 179 gl.glScalef(2.0f, 2.0f, 2.0f); 180 181 mTriangle.draw(gl); 182 183 mProjector.getCurrentModelView(gl); 184 mLabels.beginDrawing(gl, mWidth, mHeight); 185 drawLabel(gl, 0, mLabelA); 186 drawLabel(gl, 1, mLabelB); 187 drawLabel(gl, 2, mLabelC); 188 float msPFX = mWidth - mLabels.getWidth(mLabelMsPF) - 1; 189 mLabels.draw(gl, msPFX, 0, mLabelMsPF); 190 mLabels.endDrawing(gl); 191 192 drawMsPF(gl, msPFX); 193 } 194 drawMsPF(GL10 gl, float rightMargin)195 private void drawMsPF(GL10 gl, float rightMargin) { 196 long time = SystemClock.uptimeMillis(); 197 if (mStartTime == 0) { 198 mStartTime = time; 199 } 200 if (mFrames++ == SAMPLE_PERIOD_FRAMES) { 201 mFrames = 0; 202 long delta = time - mStartTime; 203 mStartTime = time; 204 mMsPerFrame = (int) (delta * SAMPLE_FACTOR); 205 } 206 if (mMsPerFrame > 0) { 207 mNumericSprite.setValue(mMsPerFrame); 208 float numWidth = mNumericSprite.width(); 209 float x = rightMargin - numWidth; 210 mNumericSprite.draw(gl, x, 0, mWidth, mHeight); 211 } 212 } 213 drawLabel(GL10 gl, int triangleVertex, int labelId)214 private void drawLabel(GL10 gl, int triangleVertex, int labelId) { 215 float x = mTriangle.getX(triangleVertex); 216 float y = mTriangle.getY(triangleVertex); 217 mScratch[0] = x; 218 mScratch[1] = y; 219 mScratch[2] = 0.0f; 220 mScratch[3] = 1.0f; 221 mProjector.project(mScratch, 0, mScratch, 4); 222 float sx = mScratch[4]; 223 float sy = mScratch[5]; 224 float height = mLabels.getHeight(labelId); 225 float width = mLabels.getWidth(labelId); 226 float tx = sx - width * 0.5f; 227 float ty = sy - height * 0.5f; 228 mLabels.draw(gl, tx, ty, labelId); 229 } 230 onSurfaceChanged(GL10 gl, int w, int h)231 public void onSurfaceChanged(GL10 gl, int w, int h) { 232 mWidth = w; 233 mHeight = h; 234 gl.glViewport(0, 0, w, h); 235 mProjector.setCurrentView(0, 0, w, h); 236 237 /* 238 * Set our projection matrix. This doesn't have to be done 239 * each time we draw, but usually a new projection needs to 240 * be set when the viewport is resized. 241 */ 242 243 float ratio = (float) w / h; 244 gl.glMatrixMode(GL10.GL_PROJECTION); 245 gl.glLoadIdentity(); 246 gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); 247 mProjector.getCurrentProjection(gl); 248 } 249 250 private int mWidth; 251 private int mHeight; 252 private Context mContext; 253 private Triangle mTriangle; 254 private int mTextureID; 255 private int mFrames; 256 private int mMsPerFrame; 257 private final static int SAMPLE_PERIOD_FRAMES = 12; 258 private final static float SAMPLE_FACTOR = 1.0f / SAMPLE_PERIOD_FRAMES; 259 private long mStartTime; 260 private LabelMaker mLabels; 261 private Paint mLabelPaint; 262 private int mLabelA; 263 private int mLabelB; 264 private int mLabelC; 265 private int mLabelMsPF; 266 private Projector mProjector; 267 private NumericSprite mNumericSprite; 268 private float[] mScratch = new float[8]; 269 } 270 271 class Triangle { Triangle()272 public Triangle() { 273 274 // Buffers to be passed to gl*Pointer() functions 275 // must be direct, i.e., they must be placed on the 276 // native heap where the garbage collector cannot 277 // move them. 278 // 279 // Buffers with multi-byte datatypes (e.g., short, int, float) 280 // must have their byte order set to native order 281 282 ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4); 283 vbb.order(ByteOrder.nativeOrder()); 284 mFVertexBuffer = vbb.asFloatBuffer(); 285 286 ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4); 287 tbb.order(ByteOrder.nativeOrder()); 288 mTexBuffer = tbb.asFloatBuffer(); 289 290 ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2); 291 ibb.order(ByteOrder.nativeOrder()); 292 mIndexBuffer = ibb.asShortBuffer(); 293 294 for (int i = 0; i < VERTS; i++) { 295 for(int j = 0; j < 3; j++) { 296 mFVertexBuffer.put(sCoords[i*3+j]); 297 } 298 } 299 300 for (int i = 0; i < VERTS; i++) { 301 for(int j = 0; j < 2; j++) { 302 mTexBuffer.put(sCoords[i*3+j] * 2.0f + 0.5f); 303 } 304 } 305 306 for(int i = 0; i < VERTS; i++) { 307 mIndexBuffer.put((short) i); 308 } 309 310 mFVertexBuffer.position(0); 311 mTexBuffer.position(0); 312 mIndexBuffer.position(0); 313 } 314 draw(GL10 gl)315 public void draw(GL10 gl) { 316 gl.glFrontFace(GL10.GL_CCW); 317 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer); 318 gl.glEnable(GL10.GL_TEXTURE_2D); 319 gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexBuffer); 320 gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, VERTS, 321 GL10.GL_UNSIGNED_SHORT, mIndexBuffer); 322 } 323 getX(int vertex)324 public float getX(int vertex) { 325 return sCoords[3*vertex]; 326 } 327 getY(int vertex)328 public float getY(int vertex) { 329 return sCoords[3*vertex+1]; 330 } 331 332 private final static int VERTS = 3; 333 334 private FloatBuffer mFVertexBuffer; 335 private FloatBuffer mTexBuffer; 336 private ShortBuffer mIndexBuffer; 337 // A unit-sided equalateral triangle centered on the origin. 338 private final static float[] sCoords = { 339 // X, Y, Z 340 -0.5f, -0.25f, 0, 341 0.5f, -0.25f, 0, 342 0.0f, 0.559016994f, 0 343 }; 344 } 345