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; 18 19 import static android.opengl.GLES10.*; 20 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.nio.ByteBuffer; 24 import java.nio.ByteOrder; 25 import java.nio.FloatBuffer; 26 import java.nio.ShortBuffer; 27 28 import javax.microedition.khronos.egl.EGLConfig; 29 import javax.microedition.khronos.opengles.GL10; 30 31 import android.content.Context; 32 import android.graphics.Bitmap; 33 import android.graphics.BitmapFactory; 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 /** 42 * A GLSurfaceView.Renderer that uses the Android-specific 43 * android.opengl.GLESXXX static OpenGL ES APIs. The static APIs 44 * expose more of the OpenGL ES features than the 45 * javax.microedition.khronos.opengles APIs, and also 46 * provide a programming model that is closer to the C OpenGL ES APIs, which 47 * may make it easier to reuse code and documentation written for the 48 * C OpenGL ES APIs. 49 * 50 */ 51 public class StaticTriangleRenderer implements GLSurfaceView.Renderer{ 52 53 public interface TextureLoader { 54 /** 55 * Load a texture into the currently bound OpenGL texture. 56 */ load(GL10 gl)57 void load(GL10 gl); 58 } 59 StaticTriangleRenderer(Context context)60 public StaticTriangleRenderer(Context context) { 61 init(context, new RobotTextureLoader()); 62 } 63 StaticTriangleRenderer(Context context, TextureLoader loader)64 public StaticTriangleRenderer(Context context, TextureLoader loader) { 65 init(context, loader); 66 } 67 init(Context context, TextureLoader loader)68 private void init(Context context, TextureLoader loader) { 69 mContext = context; 70 mTriangle = new Triangle(); 71 mTextureLoader = loader; 72 } 73 onSurfaceCreated(GL10 gl, EGLConfig config)74 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 75 /* 76 * By default, OpenGL enables features that improve quality 77 * but reduce performance. One might want to tweak that 78 * especially on software renderer. 79 */ 80 glDisable(GL_DITHER); 81 82 /* 83 * Some one-time OpenGL initialization can be made here 84 * probably based on features of this particular context 85 */ 86 glHint(GL_PERSPECTIVE_CORRECTION_HINT, 87 GL_FASTEST); 88 89 glClearColor(.5f, .5f, .5f, 1); 90 glShadeModel(GL_SMOOTH); 91 glEnable(GL_DEPTH_TEST); 92 glEnable(GL_TEXTURE_2D); 93 94 /* 95 * Create our texture. This has to be done each time the 96 * surface is created. 97 */ 98 99 int[] textures = new int[1]; 100 glGenTextures(1, textures, 0); 101 102 mTextureID = textures[0]; 103 glBindTexture(GL_TEXTURE_2D, mTextureID); 104 105 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 106 GL_NEAREST); 107 glTexParameterf(GL_TEXTURE_2D, 108 GL_TEXTURE_MAG_FILTER, 109 GL_LINEAR); 110 111 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 112 GL_CLAMP_TO_EDGE); 113 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 114 GL_CLAMP_TO_EDGE); 115 116 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 117 GL_REPLACE); 118 mTextureLoader.load(gl); 119 } 120 onDrawFrame(GL10 gl)121 public void onDrawFrame(GL10 gl) { 122 /* 123 * By default, OpenGL enables features that improve quality 124 * but reduce performance. One might want to tweak that 125 * especially on software renderer. 126 */ 127 glDisable(GL_DITHER); 128 129 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 130 GL_MODULATE); 131 132 /* 133 * Usually, the first thing one might want to do is to clear 134 * the screen. The most efficient way of doing this is to use 135 * glClear(). 136 */ 137 138 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 139 140 /* 141 * Now we're ready to draw some 3D objects 142 */ 143 144 glMatrixMode(GL_MODELVIEW); 145 glLoadIdentity(); 146 147 GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 148 149 glEnableClientState(GL_VERTEX_ARRAY); 150 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 151 152 glActiveTexture(GL_TEXTURE0); 153 glBindTexture(GL_TEXTURE_2D, mTextureID); 154 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 155 GL_REPEAT); 156 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 157 GL_REPEAT); 158 159 long time = SystemClock.uptimeMillis() % 4000L; 160 float angle = 0.090f * ((int) time); 161 162 glRotatef(angle, 0, 0, 1.0f); 163 164 mTriangle.draw(gl); 165 } 166 onSurfaceChanged(GL10 gl, int w, int h)167 public void onSurfaceChanged(GL10 gl, int w, int h) { 168 glViewport(0, 0, w, h); 169 170 /* 171 * Set our projection matrix. This doesn't have to be done 172 * each time we draw, but usually a new projection needs to 173 * be set when the viewport is resized. 174 */ 175 176 float ratio = (float) w / h; 177 glMatrixMode(GL_PROJECTION); 178 glLoadIdentity(); 179 glFrustumf(-ratio, ratio, -1, 1, 3, 7); 180 } 181 182 private Context mContext; 183 private Triangle mTriangle; 184 private int mTextureID; 185 private TextureLoader mTextureLoader; 186 187 private class RobotTextureLoader implements TextureLoader { load(GL10 gl)188 public void load(GL10 gl) { 189 InputStream is = mContext.getResources().openRawResource( 190 R.raw.robot); 191 Bitmap bitmap; 192 try { 193 bitmap = BitmapFactory.decodeStream(is); 194 } finally { 195 try { 196 is.close(); 197 } catch (IOException e) { 198 // Ignore. 199 } 200 } 201 202 GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0); 203 bitmap.recycle(); 204 } 205 } 206 207 static class Triangle { Triangle()208 public Triangle() { 209 210 // Buffers to be passed to gl*Pointer() functions 211 // must be direct, i.e., they must be placed on the 212 // native heap where the garbage collector cannot 213 // move them. 214 // 215 // Buffers with multi-byte datatypes (e.g., short, int, float) 216 // must have their byte order set to native order 217 218 ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4); 219 vbb.order(ByteOrder.nativeOrder()); 220 mFVertexBuffer = vbb.asFloatBuffer(); 221 222 ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4); 223 tbb.order(ByteOrder.nativeOrder()); 224 mTexBuffer = tbb.asFloatBuffer(); 225 226 ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2); 227 ibb.order(ByteOrder.nativeOrder()); 228 mIndexBuffer = ibb.asShortBuffer(); 229 230 // A unit-sided equilateral triangle centered on the origin. 231 float[] coords = { 232 // X, Y, Z 233 -0.5f, -0.25f, 0, 234 0.5f, -0.25f, 0, 235 0.0f, 0.559016994f, 0 236 }; 237 238 for (int i = 0; i < VERTS; i++) { 239 for(int j = 0; j < 3; j++) { 240 mFVertexBuffer.put(coords[i*3+j] * 2.0f); 241 } 242 } 243 244 for (int i = 0; i < VERTS; i++) { 245 for(int j = 0; j < 2; j++) { 246 mTexBuffer.put(coords[i*3+j] * 2.0f + 0.5f); 247 } 248 } 249 250 for(int i = 0; i < VERTS; i++) { 251 mIndexBuffer.put((short) i); 252 } 253 254 mFVertexBuffer.position(0); 255 mTexBuffer.position(0); 256 mIndexBuffer.position(0); 257 } 258 draw(GL10 gl)259 public void draw(GL10 gl) { 260 glFrontFace(GL_CCW); 261 glVertexPointer(3, GL_FLOAT, 0, mFVertexBuffer); 262 glEnable(GL_TEXTURE_2D); 263 glTexCoordPointer(2, GL_FLOAT, 0, mTexBuffer); 264 glDrawElements(GL_TRIANGLE_STRIP, VERTS, 265 GL_UNSIGNED_SHORT, mIndexBuffer); 266 } 267 268 private final static int VERTS = 3; 269 270 private FloatBuffer mFVertexBuffer; 271 private FloatBuffer mTexBuffer; 272 private ShortBuffer mIndexBuffer; 273 } 274 } 275