1b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten/*
2b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten * Copyright (C) 2011 The Android Open Source Project
3b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten *
4b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten * you may not use this file except in compliance with the License.
6b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten * You may obtain a copy of the License at
7b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten *
8b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten *
10b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten * Unless required by applicable law or agreed to in writing, software
11b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten * See the License for the specific language governing permissions and
14b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten * limitations under the License.
15b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten */
16b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
17b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenpackage com.example.nativemedia;
18b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
19b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.graphics.SurfaceTexture;
20b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.util.Log;
21b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
22b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport java.nio.ByteBuffer;
23b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport java.nio.ByteOrder;
24b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport java.nio.FloatBuffer;
25b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
26b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport javax.microedition.khronos.egl.EGLConfig;
27b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport javax.microedition.khronos.opengles.GL10;
28b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
29b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.view.MotionEvent;
30b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.content.Context;
31b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
32b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.opengl.GLES20;
33b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.opengl.GLSurfaceView;
34b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.opengl.Matrix;
35b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
36b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.hardware.SensorManager;
37b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.hardware.SensorEvent;
38b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.hardware.SensorEventListener;
39b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.hardware.Sensor;
40b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
41b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten// Remove once surfacetexture timestamps are in
42b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport java.lang.System;
43b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
44b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenimport android.util.AttributeSet;
45b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
46c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jiapublic class MyGLSurfaceView extends GLSurfaceView {
47b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
48c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    MyRenderer mRenderer;
49b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
50b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    public MyGLSurfaceView(Context context) {
51c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia        super(context, null);
52c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    }
53c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia
54c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    public MyGLSurfaceView(Context context, AttributeSet attributeSet) {
55c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia        super(context, attributeSet);
56b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        init(context);
57b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
58b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
59b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private void init(Context context) {
60b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        setEGLContextClientVersion(2);
61b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        mRenderer = new MyRenderer(context);
62b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        setRenderer(mRenderer);
63b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
64b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
65b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    @Override
66b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    public void onPause() {
67b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        super.onPause();
68b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
69b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
70b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    @Override
71b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    public void onResume() {
72b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        super.onResume();
73b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
74b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
75c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    public SurfaceTexture getSurfaceTexture() {
76b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        return mRenderer.getSurfaceTexture();
77b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
78b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten}
79b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
80b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kastenclass MyRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
81c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    private Context mContext;
82b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
83b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    public MyRenderer(Context context) {
84b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        mContext = context;
85b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
86c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia        mVertices = ByteBuffer.allocateDirect(mVerticesData.length
87b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
88c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia        mVertices.put(mVerticesData).position(0);
89b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
90b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        Matrix.setIdentityM(mSTMatrix, 0);
91b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        Matrix.setIdentityM(mMMatrix, 0);
92c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia        Matrix.rotateM(mMMatrix, 0, 20, 0, 1, 0);
93b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
94b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
95b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    public void onDrawFrame(GL10 glUnused) {
96b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        synchronized(this) {
97b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            if (updateSurface) {
98b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                mSurface.updateTexImage();
99b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
100b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                mSurface.getTransformMatrix(mSTMatrix);
101b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                updateSurface = false;
102b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            }
103b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
104b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
105b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        // Ignore the passed-in GL10 interface, and use the GLES20
106b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        // class's static methods instead.
107b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
108b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glUseProgram(mProgram);
109b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glUseProgram");
110b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
111b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
112b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
113b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
114c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia        mVertices.position(VERTICES_DATA_POS_OFFSET);
115b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
116c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia                VERTICES_DATA_STRIDE_BYTES, mVertices);
117b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glVertexAttribPointer maPosition");
118b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glEnableVertexAttribArray(maPositionHandle);
119b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glEnableVertexAttribArray maPositionHandle");
120b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
121c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia        mVertices.position(VERTICES_DATA_UV_OFFSET);
122b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, false,
123c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia                VERTICES_DATA_STRIDE_BYTES, mVertices);
124b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glVertexAttribPointer maTextureHandle");
125b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glEnableVertexAttribArray(maTextureHandle);
126b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glEnableVertexAttribArray maTextureHandle");
127b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
128b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
129b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
130b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
131b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
132b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);
133b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
134b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
135b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glDrawArrays");
136b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
137b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
138b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    public void onSurfaceChanged(GL10 glUnused, int width, int height) {
139b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        // Ignore the passed-in GL10 interface, and use the GLES20
140b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        // class's static methods instead.
141b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glViewport(0, 0, width, height);
142b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        mRatio = (float) width / height;
143b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        Matrix.frustumM(mProjMatrix, 0, -mRatio, mRatio, -1, 1, 3, 7);
144b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
145b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
146b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
147b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        // Ignore the passed-in GL10 interface, and use the GLES20
148b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        // class's static methods instead.
149b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
150b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        /* Set up alpha blending and an Android background color */
151b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glEnable(GLES20.GL_BLEND);
152b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
153b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glClearColor(0.643f, 0.776f, 0.223f, 1.0f);
154b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
155b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        /* Set up shaders and handles to their variables */
156b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        mProgram = createProgram(mVertexShader, mFragmentShader);
157b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (mProgram == 0) {
158b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            return;
159b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
160b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
161b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glGetAttribLocation aPosition");
162b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (maPositionHandle == -1) {
163b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            throw new RuntimeException("Could not get attrib location for aPosition");
164b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
165b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
166b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glGetAttribLocation aTextureCoord");
167b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (maTextureHandle == -1) {
168b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            throw new RuntimeException("Could not get attrib location for aTextureCoord");
169b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
170b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
171b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
172b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glGetUniformLocation uMVPMatrix");
173b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (muMVPMatrixHandle == -1) {
174b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            throw new RuntimeException("Could not get attrib location for uMVPMatrix");
175b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
176b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
177b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
178b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glGetUniformLocation uSTMatrix");
179b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (muMVPMatrixHandle == -1) {
180b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            throw new RuntimeException("Could not get attrib location for uSTMatrix");
181b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
182b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
183b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glGetUniformLocation uCRatio");
184b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (muMVPMatrixHandle == -1) {
185b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            throw new RuntimeException("Could not get attrib location for uCRatio");
186b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
187b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
188b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        /*
189b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten         * Create our texture. This has to be done each time the
190b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten         * surface is created.
191b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten         */
192b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
193b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        int[] textures = new int[1];
194b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glGenTextures(1, textures, 0);
195b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
196b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        mTextureID = textures[0];
197b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
198b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glBindTexture mTextureID");
199b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
200b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        // Can't do mipmapping with camera source
201b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
202b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                GLES20.GL_NEAREST);
203b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
204b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                GLES20.GL_LINEAR);
205b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        // Clamp to edge is the only option
206b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
207b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                GLES20.GL_CLAMP_TO_EDGE);
208b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
209b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                GLES20.GL_CLAMP_TO_EDGE);
210b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        checkGlError("glTexParameteri mTextureID");
211b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
212b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        /*
213b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten         * Create the SurfaceTexture that will feed this textureID, and pass it to the camera
214b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten         */
215b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
216b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        mSurface = new SurfaceTexture(mTextureID);
217b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        mSurface.setOnFrameAvailableListener(this);
218b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
219c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia        Matrix.setLookAtM(mVMatrix, 0, 0, 0, 4f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
220b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
221b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        synchronized(this) {
222b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            updateSurface = false;
223b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
224b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
225b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
226b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    synchronized public void onFrameAvailable(SurfaceTexture surface) {
227b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        /* For simplicity, SurfaceTexture calls here when it has new
228b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten         * data available.  Call may come in from some random thread,
229b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten         * so let's be safe and use synchronize. No OpenGL calls can be done here.
230b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten         */
231b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        updateSurface = true;
2323bbd3bb7fcb082eba313614f072c11c41b38ebfeGlenn Kasten        //Log.v(TAG, "onFrameAvailable " + surface.getTimestamp());
233b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
234b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
235b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private int loadShader(int shaderType, String source) {
236b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        int shader = GLES20.glCreateShader(shaderType);
237b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (shader != 0) {
238b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            GLES20.glShaderSource(shader, source);
239b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            GLES20.glCompileShader(shader);
240b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            int[] compiled = new int[1];
241b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
242b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            if (compiled[0] == 0) {
243b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                Log.e(TAG, "Could not compile shader " + shaderType + ":");
244b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
245b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                GLES20.glDeleteShader(shader);
246b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                shader = 0;
247b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            }
248b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
249b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        return shader;
250b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
251b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
252b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private int createProgram(String vertexSource, String fragmentSource) {
253b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
254b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (vertexShader == 0) {
255b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            return 0;
256b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
257b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
258b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (pixelShader == 0) {
259b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            return 0;
260b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
261b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
262b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        int program = GLES20.glCreateProgram();
263b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        if (program != 0) {
264b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            GLES20.glAttachShader(program, vertexShader);
265b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            checkGlError("glAttachShader");
266b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            GLES20.glAttachShader(program, pixelShader);
267b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            checkGlError("glAttachShader");
268b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            GLES20.glLinkProgram(program);
269b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            int[] linkStatus = new int[1];
270b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
271b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            if (linkStatus[0] != GLES20.GL_TRUE) {
272b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                Log.e(TAG, "Could not link program: ");
273b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                Log.e(TAG, GLES20.glGetProgramInfoLog(program));
274b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                GLES20.glDeleteProgram(program);
275b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten                program = 0;
276b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            }
277b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
278b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        return program;
279b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
280b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
281b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private void checkGlError(String op) {
282b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        int error;
283b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
284b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            Log.e(TAG, op + ": glError " + error);
285b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten            throw new RuntimeException(op + ": glError " + error);
286b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        }
287b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
288b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
289b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private static final int FLOAT_SIZE_BYTES = 4;
290c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    private static final int VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
291c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    private static final int VERTICES_DATA_POS_OFFSET = 0;
292c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    private static final int VERTICES_DATA_UV_OFFSET = 3;
293c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    private final float[] mVerticesData = {
294b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        // X, Y, Z, U, V
295b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        -1.0f, -1.0f, 0, 0.f, 0.f,
296b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        1.0f, -1.0f, 0, 1.f, 0.f,
297b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        -1.0f,  1.0f, 0, 0.f, 1.f,
298b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        1.0f,   1.0f, 0, 1.f, 1.f,
299b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    };
300b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
301c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    private FloatBuffer mVertices;
302b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
303b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private final String mVertexShader =
304b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "uniform mat4 uMVPMatrix;\n" +
305b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "uniform mat4 uSTMatrix;\n" +
306b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "attribute vec4 aPosition;\n" +
307b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "attribute vec4 aTextureCoord;\n" +
308b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "varying vec2 vTextureCoord;\n" +
309b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "void main() {\n" +
310c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia        "  gl_Position = uMVPMatrix * aPosition;\n" +
311b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "  vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
312b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "}\n";
313b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
314b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private final String mFragmentShader =
315b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "#extension GL_OES_EGL_image_external : require\n" +
316b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "precision mediump float;\n" +
317b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "varying vec2 vTextureCoord;\n" +
318b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "uniform samplerExternalOES sTexture;\n" +
319b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "void main() {\n" +
320b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
321b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        "}\n";
322b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
323b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private float[] mMVPMatrix = new float[16];
324b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private float[] mProjMatrix = new float[16];
325b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private float[] mMMatrix = new float[16];
326b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private float[] mVMatrix = new float[16];
327b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private float[] mSTMatrix = new float[16];
328b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
329b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private int mProgram;
330b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private int mTextureID;
331b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private int muMVPMatrixHandle;
332b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private int muSTMatrixHandle;
333b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private int maPositionHandle;
334b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private int maTextureHandle;
335b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
336b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private float mRatio = 1.0f;
337b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private SurfaceTexture mSurface;
338b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private boolean updateSurface = false;
339b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
340b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private static final String TAG = "MyRenderer";
341b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
342b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    // Magic key
343b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    private static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
344b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten
345c9034c3a484855366b663ce4b9b8c023be65ff95Ming Jia    public SurfaceTexture getSurfaceTexture() {
346b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten        return mSurface;
347b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten    }
348b66b0745d45f4c0c7620749185f7fb3306804ce3Glenn Kasten}
349