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 android.app.Activity;
20 import android.content.Context;
21 import android.opengl.GLSurfaceView;
22 import android.os.Bundle;
23 import android.view.InputDevice;
24 import android.view.KeyEvent;
25 import android.view.MotionEvent;
26 
27 import javax.microedition.khronos.egl.EGLConfig;
28 import javax.microedition.khronos.opengles.GL10;
29 
30 /**
31  * Wrapper activity demonstrating the use of {@link GLSurfaceView}, a view
32  * that uses OpenGL drawing into a dedicated surface.
33  *
34  * Shows:
35  * + How to redraw in response to user input.
36  */
37 public class TouchRotateActivity extends Activity {
38 
39     private GLSurfaceView mGLSurfaceView;
40 
41     @Override
onCreate(Bundle savedInstanceState)42     protected void onCreate(Bundle savedInstanceState) {
43         super.onCreate(savedInstanceState);
44 
45         // Create our Preview view and set it as the content of our
46         // Activity
47         mGLSurfaceView = new TouchSurfaceView(this);
48         setContentView(mGLSurfaceView);
49         mGLSurfaceView.requestFocus();
50         mGLSurfaceView.setFocusableInTouchMode(true);
51     }
52 
53     @Override
onResume()54     protected void onResume() {
55         // Ideally a game should implement onResume() and onPause()
56         // to take appropriate action when the activity looses focus
57         super.onResume();
58         mGLSurfaceView.onResume();
59     }
60 
61     @Override
onPause()62     protected void onPause() {
63         // Ideally a game should implement onResume() and onPause()
64         // to take appropriate action when the activity looses focus
65         super.onPause();
66         mGLSurfaceView.onPause();
67     }
68 
69     /**
70      * Implement a simple rotation control.
71      *
72      */
73     private static class TouchSurfaceView extends GLSurfaceView {
74 
75         private static final float TOUCH_SCALE_FACTOR = 180.0f / 320;
76         private static final float TRACKBALL_SCALE_FACTOR = 36.0f;
77         private CubeRenderer mRenderer;
78         private float mPreviousX;
79         private float mPreviousY;
80 
TouchSurfaceView(Context context)81         TouchSurfaceView(Context context) {
82             super(context);
83             mRenderer = new CubeRenderer();
84             setRenderer(mRenderer);
85             setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
86         }
87 
88         @Override
onTrackballEvent(MotionEvent e)89         public boolean onTrackballEvent(MotionEvent e) {
90             updateAngles(e.getX(), e.getY(), TRACKBALL_SCALE_FACTOR);
91             return true;
92         }
93 
94         @Override
onTouchEvent(MotionEvent e)95         public boolean onTouchEvent(MotionEvent e) {
96             final int action = e.getActionMasked();
97             if (action == MotionEvent.ACTION_MOVE) {
98                 updateAngles(e.getX() - mPreviousX, e.getY() - mPreviousY, TOUCH_SCALE_FACTOR);
99             } else if (action == MotionEvent.ACTION_DOWN) {
100                 if (e.isFromSource(InputDevice.SOURCE_MOUSE)) {
101                     requestPointerCapture();
102                 } else {
103                     releasePointerCapture();
104                 }
105             }
106             mPreviousX = e.getX();
107             mPreviousY = e.getY();
108             return true;
109         }
110 
111         @Override
onCapturedPointerEvent(MotionEvent e)112         public boolean onCapturedPointerEvent(MotionEvent e) {
113             if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
114                 releasePointerCapture();
115             } else {
116                 updateAngles(e.getX(), e.getY(), TOUCH_SCALE_FACTOR);
117             }
118             return true;
119         }
120 
121         @Override
onKeyDown(int keyCode, KeyEvent event)122         public boolean onKeyDown(int keyCode, KeyEvent event) {
123             // Release pointer capture on any key press.
124             releasePointerCapture();
125             return super.onKeyDown(keyCode, event);
126         }
127 
updateAngles(float dx, float dy, float scaleFactor)128         private void updateAngles(float dx, float dy, float scaleFactor) {
129             if (dx != 0 && dy != 0) {
130                 mRenderer.mAngleX += dx * scaleFactor;
131                 mRenderer.mAngleY += dy * scaleFactor;
132                 requestRender();
133             }
134         }
135 
136         /**
137          * Render a cube.
138          */
139         private static class CubeRenderer implements GLSurfaceView.Renderer {
CubeRenderer()140             CubeRenderer() {
141                 mCube = new Cube();
142             }
143 
144             @Override
onDrawFrame(GL10 gl)145             public void onDrawFrame(GL10 gl) {
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                 gl.glTranslatef(0, 0, -3.0f);
161                 gl.glRotatef(mAngleX, 0, 1, 0);
162                 gl.glRotatef(mAngleY, 1, 0, 0);
163 
164                 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
165                 gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
166 
167                 mCube.draw(gl);
168             }
169 
170             @Override
onSurfaceChanged(GL10 gl, int width, int height)171             public void onSurfaceChanged(GL10 gl, int width, int height) {
172                 gl.glViewport(0, 0, width, height);
173 
174                 /*
175                 * Set our projection matrix. This doesn't have to be done
176                 * each time we draw, but usually a new projection needs to
177                 * be set when the viewport is resized.
178                 */
179 
180                 float ratio = (float) width / height;
181                 gl.glMatrixMode(GL10.GL_PROJECTION);
182                 gl.glLoadIdentity();
183                 gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
184             }
185 
186             @Override
onSurfaceCreated(GL10 gl, EGLConfig config)187             public void onSurfaceCreated(GL10 gl, EGLConfig config) {
188                 /*
189                  * By default, OpenGL enables features that improve quality
190                  * but reduce performance. One might want to tweak that
191                  * especially on software renderer.
192                  */
193                 gl.glDisable(GL10.GL_DITHER);
194 
195                 /*
196                  * Some one-time OpenGL initialization can be made here
197                  * probably based on features of this particular context
198                  */
199                 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
200                         GL10.GL_FASTEST);
201 
202                 gl.glClearColor(1, 1, 1, 1);
203                 gl.glEnable(GL10.GL_CULL_FACE);
204                 gl.glShadeModel(GL10.GL_SMOOTH);
205                 gl.glEnable(GL10.GL_DEPTH_TEST);
206             }
207             private Cube mCube;
208             float mAngleX;
209             float mAngleY;
210         }
211     }
212 }
213