1 /*
2  * Copyright (C) 2012 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.mediafx;
18 
19 import android.opengl.GLES20;
20 
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 import java.nio.FloatBuffer;
24 
25 public class TextureRenderer {
26 
27     private int mProgram;
28     private int mTexSamplerHandle;
29     private int mTexCoordHandle;
30     private int mPosCoordHandle;
31 
32     private FloatBuffer mTexVertices;
33     private FloatBuffer mPosVertices;
34 
35     private int mViewWidth;
36     private int mViewHeight;
37 
38     private int mTexWidth;
39     private int mTexHeight;
40 
41     private static final String VERTEX_SHADER =
42         "attribute vec4 a_position;\n" +
43         "attribute vec2 a_texcoord;\n" +
44         "varying vec2 v_texcoord;\n" +
45         "void main() {\n" +
46         "  gl_Position = a_position;\n" +
47         "  v_texcoord = a_texcoord;\n" +
48         "}\n";
49 
50     private static final String FRAGMENT_SHADER =
51         "precision mediump float;\n" +
52         "uniform sampler2D tex_sampler;\n" +
53         "varying vec2 v_texcoord;\n" +
54         "void main() {\n" +
55         "  gl_FragColor = texture2D(tex_sampler, v_texcoord);\n" +
56         "}\n";
57 
58     private static final float[] TEX_VERTICES = {
59         0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f
60     };
61 
62     private static final float[] POS_VERTICES = {
63         -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f
64     };
65 
66     private static final int FLOAT_SIZE_BYTES = 4;
67 
init()68     public void init() {
69         // Create program
70         mProgram = GLToolbox.createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
71 
72         // Bind attributes and uniforms
73         mTexSamplerHandle = GLES20.glGetUniformLocation(mProgram,
74                 "tex_sampler");
75         mTexCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_texcoord");
76         mPosCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_position");
77 
78         // Setup coordinate buffers
79         mTexVertices = ByteBuffer.allocateDirect(
80                 TEX_VERTICES.length * FLOAT_SIZE_BYTES)
81                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
82         mTexVertices.put(TEX_VERTICES).position(0);
83         mPosVertices = ByteBuffer.allocateDirect(
84                 POS_VERTICES.length * FLOAT_SIZE_BYTES)
85                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
86         mPosVertices.put(POS_VERTICES).position(0);
87     }
88 
tearDown()89     public void tearDown() {
90         GLES20.glDeleteProgram(mProgram);
91     }
92 
updateTextureSize(int texWidth, int texHeight)93     public void updateTextureSize(int texWidth, int texHeight) {
94         mTexWidth = texWidth;
95         mTexHeight = texHeight;
96         computeOutputVertices();
97     }
98 
updateViewSize(int viewWidth, int viewHeight)99     public void updateViewSize(int viewWidth, int viewHeight) {
100         mViewWidth = viewWidth;
101         mViewHeight = viewHeight;
102         computeOutputVertices();
103     }
104 
renderTexture(int texId)105     public void renderTexture(int texId) {
106         // Bind default FBO
107         GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
108 
109         // Use our shader program
110         GLES20.glUseProgram(mProgram);
111         GLToolbox.checkGlError("glUseProgram");
112 
113         // Set viewport
114         GLES20.glViewport(0, 0, mViewWidth, mViewHeight);
115         GLToolbox.checkGlError("glViewport");
116 
117         // Disable blending
118         GLES20.glDisable(GLES20.GL_BLEND);
119 
120         // Set the vertex attributes
121         GLES20.glVertexAttribPointer(mTexCoordHandle, 2, GLES20.GL_FLOAT, false,
122                 0, mTexVertices);
123         GLES20.glEnableVertexAttribArray(mTexCoordHandle);
124         GLES20.glVertexAttribPointer(mPosCoordHandle, 2, GLES20.GL_FLOAT, false,
125                 0, mPosVertices);
126         GLES20.glEnableVertexAttribArray(mPosCoordHandle);
127         GLToolbox.checkGlError("vertex attribute setup");
128 
129         // Set the input texture
130         GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
131         GLToolbox.checkGlError("glActiveTexture");
132         GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
133         GLToolbox.checkGlError("glBindTexture");
134         GLES20.glUniform1i(mTexSamplerHandle, 0);
135 
136         // Draw
137         GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
138         GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
139         GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
140     }
141 
computeOutputVertices()142     private void computeOutputVertices() {
143         if (mPosVertices != null) {
144             float imgAspectRatio = mTexWidth / (float)mTexHeight;
145             float viewAspectRatio = mViewWidth / (float)mViewHeight;
146             float relativeAspectRatio = viewAspectRatio / imgAspectRatio;
147             float x0, y0, x1, y1;
148             if (relativeAspectRatio > 1.0f) {
149                 x0 = -1.0f / relativeAspectRatio;
150                 y0 = -1.0f;
151                 x1 = 1.0f / relativeAspectRatio;
152                 y1 = 1.0f;
153             } else {
154                 x0 = -1.0f;
155                 y0 = -relativeAspectRatio;
156                 x1 = 1.0f;
157                 y1 = relativeAspectRatio;
158             }
159             float[] coords = new float[] { x0, y0, x1, y0, x0, y1, x1, y1 };
160             mPosVertices.put(coords).position(0);
161         }
162     }
163 }
164