1 /* 2 * Copyright (C) 2007 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.android.objviewer; 18 19 import android.app.Activity; 20 import android.content.AssetManager; 21 import android.content.Context; 22 import android.graphics.Canvas; 23 import android.graphics.OpenGLContext; 24 import android.graphics.Paint; 25 import android.graphics.glutils.GLView; 26 import android.graphics.glutils.Object3D; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.Message; 30 import android.os.SystemClock; 31 import android.view.KeyEvent; 32 import android.view.View; 33 import android.view.Window; 34 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.util.ArrayList; 38 import java.util.List; 39 40 import javax.microedition.khronos.opengles.GL10; 41 42 class OBJView extends View { 43 44 // Mathematical constants 45 private static final float PI = (float)Math.PI; 46 private static final float TWO_PI = (float)(2.0*Math.PI); 47 private static final float PI_OVER_TWO = (float)(Math.PI/2.0); 48 49 // Ambient light to apply 50 // private float[] lightModelAmbient = { 0.0f, 0.0f, 0.0f, 1.0f }; 51 private float[] lightModelAmbient = { 0.2f, 0.2f, 0.2f, 1.0f }; 52 53 // Paint object for drawing the FPS display 54 private Paint paint = new Paint(); 55 56 // GLView object to manage drawing 57 private GLView glView = new GLView(); 58 59 private boolean initialized = false; 60 61 private OpenGLContext mGLContext; 62 63 // Next time to draw 64 private long mNextTime; 65 66 // View transformation controlled by UI 67 private float mRotAngle = 0.0f; 68 private float mRotVelocity = 1.0f; 69 private float mTiltAngle = 0.0f; 70 71 // Object bounds 72 private float mCenterX = 0.0f; 73 private float mCenterY = 0.0f; 74 private float mCenterZ = 0.0f; 75 private float mScale = 1.0f; 76 77 // Light direction 78 private float[] mLightDir = { 0.0f, 0.0f, 1.0f, 0.0f }; 79 80 public OBJView(Context context) { 81 super(context); 82 83 mGLContext = new OpenGLContext(OpenGLContext.DEPTH_BUFFER); 84 85 Message msg = mHandler.obtainMessage(INVALIDATE); 86 mNextTime = SystemClock.uptimeMillis() + 100; 87 mHandler.sendMessageAtTime(msg, mNextTime); 88 89 requestFocus(); 90 } 91 92 public void reset() { 93 initialized = false; 94 95 mRotAngle = 0.0f; 96 mRotVelocity = 1.0f; 97 mTiltAngle = 0.0f; 98 99 mCenterX = 0.0f; 100 mCenterY = 0.0f; 101 mCenterZ = 0.0f; 102 mScale = 1.0f; 103 } 104 105 public boolean onKeyDown(int keyCode, KeyEvent event) { 106 // Hand the key to the GLView object first 107 if (glView.processKey(keyCode)) { 108 return true; 109 } 110 111 switch (keyCode) { 112 case KeyEvent.KEYCODE_DPAD_LEFT: 113 mRotVelocity -= 1.0f; 114 break; 115 116 case KeyEvent.KEYCODE_DPAD_RIGHT: 117 mRotVelocity += 1.0f; 118 break; 119 120 case KeyEvent.KEYCODE_DPAD_CENTER: 121 mRotVelocity = 0.0f; 122 break; 123 124 case KeyEvent.KEYCODE_DPAD_UP: 125 mTiltAngle -= 360.0f/24.0f; 126 break; 127 128 case KeyEvent.KEYCODE_DPAD_DOWN: 129 mTiltAngle += 360.0f/24.0f; 130 break; 131 132 case KeyEvent.KEYCODE_U: 133 OBJViewer.nextObject(); 134 reset(); 135 break; 136 137 default: 138 return super.onKeyDown(keyCode, event); 139 } 140 141 return true; 142 } 143 144 private void init(GL10 gl) { 145 glView.reset(); 146 147 paint.setColor(0xffffffff); 148 149 gl.glEnable(gl.GL_DEPTH_TEST); 150 151 gl.glDisable(gl.GL_SCISSOR_TEST); 152 153 // Some quality settings... 154 gl.glEnable(gl.GL_DITHER); 155 156 gl.glShadeModel(gl.GL_SMOOTH); 157 158 gl.glEnable(gl.GL_CULL_FACE); 159 gl.glFrontFace(gl.GL_CCW); 160 161 gl.glClearColor(0, 0, 0, 1); 162 163 gl.glLightModelf(gl.GL_LIGHT_MODEL_TWO_SIDE, 0); 164 gl.glLightModelfv(gl.GL_LIGHT_MODEL_AMBIENT, lightModelAmbient, 0); 165 } 166 167 @Override 168 protected void onDraw(Canvas canvas) { 169 GL10 gl = (GL10)mGLContext.getGL(); 170 mGLContext.makeCurrent(this); 171 172 if (!initialized) { 173 init(gl); 174 initialized = true; 175 176 // Load the object 177 Object3D obj = OBJViewer.getObject(); 178 179 // Compute a scale factor and translation to bring it 180 // into view 181 mCenterX = (obj.getBoundsMinX() + obj.getBoundsMaxX())/2.0f; 182 mCenterY = (obj.getBoundsMinY() + obj.getBoundsMaxY())/2.0f; 183 mCenterZ = (obj.getBoundsMinZ() + obj.getBoundsMaxZ())/2.0f; 184 float spanX = obj.getBoundsMaxX() - obj.getBoundsMinX(); 185 float spanY = obj.getBoundsMaxY() - obj.getBoundsMinY(); 186 float spanZ = obj.getBoundsMaxZ() - obj.getBoundsMinZ(); 187 float maxSpan = Math.max(spanX, spanY); 188 maxSpan = Math.max(maxSpan, spanZ); 189 mScale = 2.0f/maxSpan; 190 } 191 192 int w = getWidth(); 193 int h = getHeight(); 194 gl.glViewport(0, 0, w, h); 195 196 float ratio = (float)w/h; 197 glView.setAspectRatio(ratio); 198 199 // Clear buffers 200 gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT); 201 202 // Set up the projection and view 203 glView.setProjection(gl); 204 glView.setView(gl); 205 206 // Set up lighting 207 gl.glMatrixMode(gl.GL_MODELVIEW); 208 gl.glEnable(gl.GL_LIGHTING); 209 gl.glEnable(gl.GL_LIGHT0); 210 gl.glLightfv(gl.GL_LIGHT0, gl.GL_POSITION, mLightDir, 0); 211 glView.setLights(gl, gl.GL_LIGHT0); 212 213 // Rotate the viewpoint around the model 214 gl.glRotatef(mTiltAngle, 1, 0, 0); 215 gl.glRotatef(mRotAngle, 0, 1, 0); 216 217 // Scale object to fit in [-1, 1] 218 gl.glScalef(mScale, mScale, mScale); 219 220 // Center the object at the origin 221 gl.glTranslatef(-mCenterX, -mCenterY, -mCenterZ); 222 223 // Increment the rotation angle 224 mRotAngle += mRotVelocity; 225 if (mRotAngle < 0.0f) { 226 mRotAngle += 360.0f; 227 } 228 if (mRotAngle > 360.0f) { 229 mRotAngle -= 360.0f; 230 } 231 232 // Draw the object 233 Object3D object = OBJViewer.getObject(); 234 object.draw(gl); 235 236 // Allow GL to complete 237 mGLContext.post(); 238 239 // Draw GLView messages and/or FPS 240 glView.showMessages(canvas); 241 glView.setNumTriangles(object.getNumTriangles()); 242 glView.showStatistics(canvas, w); 243 } 244 245 private static final int INVALIDATE = 1; 246 247 private final Handler mHandler = new Handler() { 248 public void handleMessage(Message msg) { 249 if (msg.what == INVALIDATE) { 250 invalidate(); 251 msg = obtainMessage(INVALIDATE); 252 long current = SystemClock.uptimeMillis(); 253 if (mNextTime < current) { 254 mNextTime = current + 20; 255 } 256 sendMessageAtTime(msg, mNextTime); 257 mNextTime += 20; 258 } 259 } 260 }; 261 } 262 263 264 public class OBJViewer extends Activity { 265 266 private static Object3D object = null; 267 268 private static List<String> objectFiles = new ArrayList<String>(); 269 private static int objectIndex = 0; 270 271 static { 272 objectFiles.add("world.gles"); 273 objectFiles.add("al.gles"); 274 objectFiles.add("apple.gles"); 275 objectFiles.add("dolphins.gles"); 276 objectFiles.add("f16.gles"); 277 objectFiles.add("flowers.gles"); 278 objectFiles.add("porsche.gles"); 279 objectFiles.add("rosevase.gles"); 280 objectFiles.add("shuttle.gles"); 281 objectFiles.add("soccerball.gles"); 282 } 283 284 private int readInt16(InputStream is) throws Exception { 285 return is.read() | (is.read() << 8); 286 } 287 288 public static Object3D getObject() { 289 return object; 290 } 291 292 public static void nextObject() { 293 try { 294 objectIndex = (objectIndex + 1) % objectFiles.size(); 295 object.load(objectFiles.get(objectIndex)); 296 } catch (IOException e) { 297 throw new RuntimeException(e); 298 } 299 } 300 301 @Override protected void onCreate(Bundle icicle) { 302 super.onCreate(icicle); 303 304 // Get rid of the title 305 requestWindowFeature(Window.FEATURE_NO_TITLE); 306 // Make sure we're not drawing a background 307 setTheme(R.style.Theme); 308 setContentView(new OBJView((Context)getApplication())); 309 310 if (object == null) { 311 try { 312 final AssetManager am = getAssets(); 313 this.object = new Object3D() { 314 public InputStream readFile(String filename) 315 throws IOException { 316 return am.open(filename); 317 318 } 319 }; 320 object.load(objectFiles.get(0)); 321 } catch (Exception e) { 322 throw new RuntimeException(e); 323 } 324 } 325 } 326 327 @Override protected void onResume() { 328 super.onResume(); 329 } 330 331 @Override protected void onStop() { 332 super.onStop(); 333 } 334 } 335