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 
OBJView(Context context)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 
reset()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 
onKeyDown(int keyCode, KeyEvent event)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 
init(GL10 gl)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
onDraw(Canvas canvas)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 
readInt16(InputStream is)284     private int readInt16(InputStream is) throws Exception {
285         return is.read() | (is.read() << 8);
286     }
287 
getObject()288     public static Object3D getObject() {
289         return object;
290     }
291 
nextObject()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 
onCreate(Bundle icicle)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 
onResume()327     @Override protected void onResume() {
328         super.onResume();
329     }
330 
onStop()331     @Override protected void onStop() {
332         super.onStop();
333     }
334 }
335