155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala/*
255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala * Copyright (C) 2011 The Android Open Source Project
355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala *
455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License");
555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala * you may not use this file except in compliance with the License.
655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala * You may obtain a copy of the License at
755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala *
855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala *      http://www.apache.org/licenses/LICENSE-2.0
955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala *
1055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala * Unless required by applicable law or agreed to in writing, software
1155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS,
1255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala * See the License for the specific language governing permissions and
1455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala * limitations under the License.
1555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala */
1655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
1755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalapackage com.android.gl2cameraeye;
1855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
1955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport java.io.IOException;
2055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport java.nio.ByteBuffer;
2155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport java.nio.ByteOrder;
2255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport java.nio.FloatBuffer;
2355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
2455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport javax.microedition.khronos.egl.EGLConfig;
2555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport javax.microedition.khronos.opengles.GL10;
2655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
2755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.app.Activity;
2855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.content.pm.ActivityInfo;
2955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.os.Bundle;
3055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.view.MotionEvent;
3155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.content.Context;
3255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.util.Log;
3355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
3455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.opengl.GLES20;
3555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.opengl.GLSurfaceView;
3655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.opengl.GLUtils;
3755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.opengl.Matrix;
3855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
3955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.graphics.SurfaceTexture;
4055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
4155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.hardware.Camera;
4255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.hardware.SensorManager;
4355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.hardware.SensorEvent;
4455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.hardware.SensorEventListener;
4555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaimport android.hardware.Sensor;
4655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
4755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalapublic class GL2CameraEye extends Activity {
4855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    @Override
4955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    protected void onCreate(Bundle savedInstanceState) {
5055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        super.onCreate(savedInstanceState);
5155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mGLView = new CamGLSurfaceView(this);
5255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        setContentView(mGLView);
5355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
5455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
5555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
5655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    @Override
5755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    protected void onPause() {
5855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        super.onPause();
5955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mGLView.onPause();
6055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
6155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
6255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    @Override
6355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    protected void onResume() {
6455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        super.onResume();
6555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mGLView.onResume();
6655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
6755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
6855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private GLSurfaceView mGLView;
6955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala}
7055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
7155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaclass CamGLSurfaceView extends GLSurfaceView implements SensorEventListener {
7255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public CamGLSurfaceView(Context context) {
7355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        super(context);
7455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        setEGLContextClientVersion(2);
7555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mRenderer = new CamRenderer(context);
7655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        setRenderer(mRenderer);
7755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
7855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
7955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mAcceleration = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
8055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
8155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
8255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public boolean onTouchEvent(final MotionEvent event) {
8355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        queueEvent(new Runnable(){
8455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                public void run() {
8555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                mRenderer.setPosition(event.getX() / getWidth(),
8655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                                      event.getY() / getHeight());
8755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            }});
8855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        return true;
8955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
9055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
9155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    @Override
9255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void onPause() {
9355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        super.onPause();
9455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mCamera.stopPreview();
9555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mCamera.release();
9655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
9755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mSensorManager.unregisterListener(this);
9855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
9955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
10055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    @Override
10155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void onResume() {
10255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mCamera = Camera.open();
10355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        Camera.Parameters p = mCamera.getParameters();
10455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // No changes to default camera parameters
10555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mCamera.setParameters(p);
10655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
10755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        queueEvent(new Runnable(){
10855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                public void run() {
10955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                    mRenderer.setCamera(mCamera);
11055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                }});
11155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
11255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mSensorManager.registerListener(this, mAcceleration, SensorManager.SENSOR_DELAY_GAME);
11355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        super.onResume();
11455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
11555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
11655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void onSensorChanged(SensorEvent event) {
11755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
11855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            final float[] accelerationVector = event.values;
11955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            queueEvent(new Runnable(){
12055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                    public void run() {
12155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                        mRenderer.setAcceleration(accelerationVector);
12255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                    }});
12355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
12455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
12555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
12655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void onAccuracyChanged(Sensor sensor, int accuracy) {
12755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // Ignoring sensor accuracy changes.
12855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
12955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
13055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    CamRenderer mRenderer;
13155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    Camera mCamera;
13255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
13355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    SensorManager mSensorManager;
13455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    Sensor mAcceleration;
13555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala}
13655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
13755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvalaclass CamRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
13855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
13955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public CamRenderer(Context context) {
14055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mContext = context;
14155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
14255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
14355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
14455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mTriangleVertices.put(mTriangleVerticesData).position(0);
14555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
14655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        Matrix.setIdentityM(mSTMatrix, 0);
14755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        Matrix.setIdentityM(mMMatrix, 0);
14855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
14955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        float[] defaultAcceleration = {0.f,0.f,0.f};
15055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        setAcceleration(defaultAcceleration);
15155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mPos[0] = 0.f;
15255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mPos[1] = 0.f;
15355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mPos[2] = 0.f;
15455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mVel[0] = 0.f;
15555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mVel[1] = 0.f;
15655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mVel[2] = 0.f;
15755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
15855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
15955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
16055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    /* The following set methods are not synchronized, so should only
16155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala     * be called within the rendering thread context. Use GLSurfaceView.queueEvent for safe access.
16255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala     */
16355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void setPosition(float x, float y) {
16455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        /* Map from screen (0,0)-(1,1) to scene coordinates */
16555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mPos[0] = (x*2-1)*mRatio;
16655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mPos[1] = (-y)*2+1;
16755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mPos[2] = 0.f;
16855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mVel[0] = 0;
16955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mVel[1] = 0;
17055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mVel[2] = 0;
17155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
17255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
17355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void setCamera(Camera camera) {
17455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mCamera = camera;
17555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        Camera.Size previewSize = camera.getParameters().getPreviewSize();
17655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mCameraRatio = (float)previewSize.width/previewSize.height;
17755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
17855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
17955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void setAcceleration(float[] accelerationVector) {
18055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mGForce[0] = accelerationVector[0];
18155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mGForce[1] = accelerationVector[1];
18255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mGForce[2] = accelerationVector[2];
18355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
18455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
18555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void onDrawFrame(GL10 glUnused) {
18655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        synchronized(this) {
18755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            if (updateSurface) {
18855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                mSurface.updateTexImage();
18955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
19055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                mSurface.getTransformMatrix(mSTMatrix);
19155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                long timestamp = mSurface.getTimestamp();
19255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                doPhysics(timestamp);
19355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
19455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                updateSurface = false;
19555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            }
19655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
19755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
19855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // Ignore the passed-in GL10 interface, and use the GLES20
19955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // class's static methods instead.
20055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
20155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glUseProgram(mProgram);
20255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glUseProgram");
20355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
20455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
20555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
20655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
20755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
20855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
20955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
21055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glVertexAttribPointer maPosition");
21155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glEnableVertexAttribArray(maPositionHandle);
21255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glEnableVertexAttribArray maPositionHandle");
21355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
21455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
21555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, false,
21655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
21755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glVertexAttribPointer maTextureHandle");
21855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glEnableVertexAttribArray(maTextureHandle);
21955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glEnableVertexAttribArray maTextureHandle");
22055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
22155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
22255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
22355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
22455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
22555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);
22655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glUniform1f(muCRatioHandle, mCameraRatio);
22755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
22855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
22955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glDrawArrays");
23055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
23155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
23255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void onSurfaceChanged(GL10 glUnused, int width, int height) {
23355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // Ignore the passed-in GL10 interface, and use the GLES20
23455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // class's static methods instead.
23555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glViewport(0, 0, width, height);
23655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mRatio = (float) width / height;
23755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        Matrix.frustumM(mProjMatrix, 0, -mRatio, mRatio, -1, 1, 3, 7);
23855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
23955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
24055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
24155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // Ignore the passed-in GL10 interface, and use the GLES20
24255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // class's static methods instead.
24355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
24455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        /* Set up alpha blending and an Android background color */
24555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glEnable(GLES20.GL_BLEND);
24655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
24755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glClearColor(0.643f, 0.776f, 0.223f, 1.0f);
24855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
24955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        /* Set up shaders and handles to their variables */
25055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mProgram = createProgram(mVertexShader, mFragmentShader);
25155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (mProgram == 0) {
25255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            return;
25355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
25455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
25555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glGetAttribLocation aPosition");
25655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (maPositionHandle == -1) {
25755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            throw new RuntimeException("Could not get attrib location for aPosition");
25855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
25955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
26055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glGetAttribLocation aTextureCoord");
26155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (maTextureHandle == -1) {
26255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            throw new RuntimeException("Could not get attrib location for aTextureCoord");
26355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
26455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
26555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
26655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glGetUniformLocation uMVPMatrix");
26755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (muMVPMatrixHandle == -1) {
26855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            throw new RuntimeException("Could not get attrib location for uMVPMatrix");
26955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
27055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
27155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
27255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glGetUniformLocation uSTMatrix");
27355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (muMVPMatrixHandle == -1) {
27455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            throw new RuntimeException("Could not get attrib location for uSTMatrix");
27555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
27655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
27755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        muCRatioHandle = GLES20.glGetUniformLocation(mProgram, "uCRatio");
27855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glGetUniformLocation uCRatio");
27955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (muMVPMatrixHandle == -1) {
28055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            throw new RuntimeException("Could not get attrib location for uCRatio");
28155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
28255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
28355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        /*
28455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         * Create our texture. This has to be done each time the
28555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         * surface is created.
28655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         */
28755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
28855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        int[] textures = new int[1];
28955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glGenTextures(1, textures, 0);
29055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
29155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mTextureID = textures[0];
29255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
29355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glBindTexture mTextureID");
29455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
29555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // Can't do mipmapping with camera source
29655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
29755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                GLES20.GL_NEAREST);
29855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
29955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                GLES20.GL_LINEAR);
30055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // Clamp to edge is the only option
30155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
30255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                GLES20.GL_CLAMP_TO_EDGE);
30355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
30455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                GLES20.GL_CLAMP_TO_EDGE);
30555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        checkGlError("glTexParameteri mTextureID");
30655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
30755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        /*
30855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         * Create the SurfaceTexture that will feed this textureID, and pass it to the camera
30955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         */
31055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
31155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mSurface = new SurfaceTexture(mTextureID);
31255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mSurface.setOnFrameAvailableListener(this);
31355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        try {
31455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            mCamera.setPreviewTexture(mSurface);
31555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        } catch (IOException t) {
31655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            Log.e(TAG, "Cannot set preview texture target!");
31755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
31855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
31955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        /* Start the camera */
32055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mCamera.startPreview();
32155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
32255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        Matrix.setLookAtM(mVMatrix, 0, 0, 0, 5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
32355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
32455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        mLastTime = 0;
32555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
32655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        synchronized(this) {
32755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            updateSurface = false;
32855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
32955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
33055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
33155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    synchronized public void onFrameAvailable(SurfaceTexture surface) {
33255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        /* For simplicity, SurfaceTexture calls here when it has new
33355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         * data available.  Call may come in from some random thread,
33455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         * so let's be safe and use synchronize. No OpenGL calls can be done here.
33555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         */
33655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        updateSurface = true;
33755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
33855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
33955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private void doPhysics(long timestamp) {
34055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        /*
34155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         * Move the camera surface around based on some simple spring physics with drag
34255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala         */
34355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
34455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (mLastTime == 0)
34555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            mLastTime = timestamp;
34655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
34755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        float deltaT = (timestamp - mLastTime)/1000000000.f; // To seconds
34855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
34955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        float springStrength = 20.f;
35055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        float frictionCoeff = 10.f;
35155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        float mass = 10.f;
35255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        float gMultiplier = 4.f;
35355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        /* Only update physics every 30 ms */
35455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (deltaT > 0.030f) {
35555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            mLastTime = timestamp;
35655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
35755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            float[] totalForce = new float[3];
35855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            totalForce[0] = -mPos[0] * springStrength - mVel[0]*frictionCoeff + gMultiplier*mGForce[0]*mass;
35955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            totalForce[1] = -mPos[1] * springStrength - mVel[1]*frictionCoeff + gMultiplier*mGForce[1]*mass;
36055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            totalForce[2] = -mPos[2] * springStrength - mVel[2]*frictionCoeff + gMultiplier*mGForce[2]*mass;
36155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
36255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            float[] accel = new float[3];
36355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            accel[0] = totalForce[0]/mass;
36455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            accel[1] = totalForce[1]/mass;
36555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            accel[2] = totalForce[2]/mass;
36655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
36755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            /* Not a very accurate integrator */
36855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            mVel[0] = mVel[0] + accel[0]*deltaT;
36955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            mVel[1] = mVel[1] + accel[1]*deltaT;
37055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            mVel[2] = mVel[2] + accel[2]*deltaT;
37155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
37255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            mPos[0] = mPos[0] + mVel[0]*deltaT;
37355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            mPos[1] = mPos[1] + mVel[1]*deltaT;
37455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            mPos[2] = mPos[2] + mVel[2]*deltaT;
37555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
37655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            Matrix.setIdentityM(mMMatrix, 0);
37755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            Matrix.translateM(mMMatrix, 0, mPos[0], mPos[1], mPos[2]);
37855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
37955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
38055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
38155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
38255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private int loadShader(int shaderType, String source) {
38355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        int shader = GLES20.glCreateShader(shaderType);
38455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (shader != 0) {
38555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            GLES20.glShaderSource(shader, source);
38655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            GLES20.glCompileShader(shader);
38755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            int[] compiled = new int[1];
38855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
38955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            if (compiled[0] == 0) {
39055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                Log.e(TAG, "Could not compile shader " + shaderType + ":");
39155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
39255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                GLES20.glDeleteShader(shader);
39355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                shader = 0;
39455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            }
39555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
39655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        return shader;
39755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
39855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
39955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private int createProgram(String vertexSource, String fragmentSource) {
40055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
40155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (vertexShader == 0) {
40255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            return 0;
40355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
40455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
40555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (pixelShader == 0) {
40655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            return 0;
40755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
40855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
40955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        int program = GLES20.glCreateProgram();
41055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        if (program != 0) {
41155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            GLES20.glAttachShader(program, vertexShader);
41255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            checkGlError("glAttachShader");
41355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            GLES20.glAttachShader(program, pixelShader);
41455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            checkGlError("glAttachShader");
41555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            GLES20.glLinkProgram(program);
41655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            int[] linkStatus = new int[1];
41755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
41855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            if (linkStatus[0] != GLES20.GL_TRUE) {
41955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                Log.e(TAG, "Could not link program: ");
42055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                Log.e(TAG, GLES20.glGetProgramInfoLog(program));
42155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                GLES20.glDeleteProgram(program);
42255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala                program = 0;
42355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            }
42455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
42555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        return program;
42655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
42755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
42855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private void checkGlError(String op) {
42955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        int error;
43055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
43155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            Log.e(TAG, op + ": glError " + error);
43255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala            throw new RuntimeException(op + ": glError " + error);
43355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        }
43455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    }
43555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
43655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private static final int FLOAT_SIZE_BYTES = 4;
43755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
43855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
43955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
44055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private final float[] mTriangleVerticesData = {
44155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        // X, Y, Z, U, V
44255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        -1.0f, -1.0f, 0, 0.f, 0.f,
44355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        1.0f, -1.0f, 0, 1.f, 0.f,
44455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        -1.0f,  1.0f, 0, 0.f, 1.f,
44555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        1.0f,   1.0f, 0, 1.f, 1.f,
44655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    };
44755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
44855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private FloatBuffer mTriangleVertices;
44955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
45055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private final String mVertexShader =
45155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "uniform mat4 uMVPMatrix;\n" +
45255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "uniform mat4 uSTMatrix;\n" +
45355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "uniform float uCRatio;\n" +
45455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "attribute vec4 aPosition;\n" +
45555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "attribute vec4 aTextureCoord;\n" +
45655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "varying vec2 vTextureCoord;\n" +
45755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "varying vec2 vTextureNormCoord;\n" +
45855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "void main() {\n" +
45955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "  vec4 scaledPos = aPosition;\n" +
46055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "  scaledPos.x = scaledPos.x * uCRatio;\n" +
46155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "  gl_Position = uMVPMatrix * scaledPos;\n" +
46255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "  vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
46355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "  vTextureNormCoord = aTextureCoord.xy;\n" +
46455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "}\n";
46555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
46655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private final String mFragmentShader =
46755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "#extension GL_OES_EGL_image_external : require\n" +
46855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "precision mediump float;\n" +
46955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "varying vec2 vTextureCoord;\n" +
47055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "varying vec2 vTextureNormCoord;\n" +
47155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "uniform samplerExternalOES sTexture;\n" +
47255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "void main() {\n" +
47355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
47455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "  gl_FragColor.a = 1.0-min(length(vTextureNormCoord-0.5)*2.0,1.0);\n" +
47555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala        "}\n";
47655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
47755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float[] mMVPMatrix = new float[16];
47855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float[] mProjMatrix = new float[16];
47955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float[] mMMatrix = new float[16];
48055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float[] mVMatrix = new float[16];
48155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float[] mSTMatrix = new float[16];
48255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
48355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private int mProgram;
48455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private int mTextureID;
48555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private int muMVPMatrixHandle;
48655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private int muSTMatrixHandle;
48755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private int muCRatioHandle;
48855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private int maPositionHandle;
48955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private int maTextureHandle;
49055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
49155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float mRatio = 1.0f;
49255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float mCameraRatio = 1.0f;
49355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float[] mVel = new float[3];
49455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float[] mPos = new float[3];
49555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private float[] mGForce = new float[3];
49655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
49755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private long mLastTime;
49855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
49955c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private SurfaceTexture mSurface;
50055c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private Camera mCamera;
50155c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private boolean updateSurface = false;
50255c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
50355c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private Context mContext;
50455c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private static String TAG = "CamRenderer";
50555c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala
50655c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    // Magic key
50755c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala    private static int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
50855c617aa2d49e3403f8700b173dc9220654deb74Eino-Ville Talvala}
509