From b7a19da2d866fc56e285e3e17b3118121ca96cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=97=B6=E6=9D=83?= Date: Mon, 27 Dec 2021 17:54:40 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E9=9C=80=E6=B1=82=E3=80=91=E6=8F=90?= =?UTF-8?q?=E4=BA=A4opengl=20es=E6=95=99=E7=A8=8B=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ly/avfoundation/MainActivity.java | 25 +- .../avfoundation/gles/ESTransform.java | 217 ++++++++++++++++++ .../gles/TextureWrapRenderer.java | 196 ++++++++++++++++ .../avfoundation/gles/TriangleProgram.java | 212 +++++++++++++++++ .../avfoundation/render/TriangleRender.java | 40 ++++ .../avfoundation/render/TriangleRender2.java | 143 ++++++++++++ .../fragment/OpenGLESFragment.java | 40 ++++ .../src/main/res/layout/opengles_fragment.xml | 10 + 8 files changed, 879 insertions(+), 4 deletions(-) create mode 100644 project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/ESTransform.java create mode 100644 project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/TextureWrapRenderer.java create mode 100644 project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/TriangleProgram.java create mode 100644 project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/render/TriangleRender.java create mode 100644 project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/render/TriangleRender2.java create mode 100644 project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/fragment/OpenGLESFragment.java create mode 100644 project/android/AVFoundation/app/src/main/res/layout/opengles_fragment.xml diff --git a/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/MainActivity.java b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/MainActivity.java index 99d7aca..619a451 100644 --- a/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/MainActivity.java +++ b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/MainActivity.java @@ -17,6 +17,7 @@ import androidx.fragment.app.FragmentActivity; import com.ly.avfoundation.fragment.CaptureFragment; import com.ly.avfoundation.fragment.HomeFragment; +import com.ly.avfoundation.fragment.OpenGLESFragment; public class MainActivity extends FragmentActivity implements View.OnClickListener { private static final String TAG = "[MainActivity]"; @@ -26,10 +27,11 @@ public class MainActivity extends FragmentActivity implements View.OnClickListen private RelativeLayout mPlayerBtn; private RelativeLayout mEditorBtn; - private final static int FRAGMENT_TYPE_HOME = 1; - private final static int FRAGMENT_TYPE_CAPTURE = 2; - private final static int FRAGMENT_TYPE_PLAYER = 3; - private final static int FRAGMENT_TYPE_EDITOR = 4; + private final static int FRAGMENT_TYPE_HOME = 1; + private final static int FRAGMENT_TYPE_CAPTURE = 2; + private final static int FRAGMENT_TYPE_PLAYER = 3; + private final static int FRAGMENT_TYPE_EDITOR = 4; + private final static int FRAGMENT_TYPE_OPENGLES = 5; private int mFragmentType; @Override @@ -76,6 +78,7 @@ public class MainActivity extends FragmentActivity implements View.OnClickListen this.handleToCaptureFragment(); break; case R.id.buttom_bar_btn_player: + this.handleToOpenGLESFragment(); break; case R.id.buttom_bar_btn_editor: break; @@ -112,6 +115,20 @@ public class MainActivity extends FragmentActivity implements View.OnClickListen mFragmentType = FRAGMENT_TYPE_CAPTURE; } + private void handleToOpenGLESFragment() { + if (mFragmentType == FRAGMENT_TYPE_OPENGLES) { + return; + } + + Bundle saveInstanceState = new Bundle(); + OpenGLESFragment fragment = OpenGLESFragment.newInstance(saveInstanceState); + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.buttom_bar_main, fragment) + .commit(); + mFragmentType = FRAGMENT_TYPE_OPENGLES; + } + @SuppressLint("WrongConstant") public static boolean hasPermission(Context context, String permission) { if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED || diff --git a/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/ESTransform.java b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/ESTransform.java new file mode 100644 index 0000000..6322f47 --- /dev/null +++ b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/ESTransform.java @@ -0,0 +1,217 @@ +package com.ly.avfoundation.avfoundation.gles; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +public class ESTransform { + + public ESTransform() { + mMatrixFloatBuffer = ByteBuffer.allocateDirect(16 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + } + + public void scale ( float sx, float sy, float sz ) { + mMatrix[0 * 4 + 0] *= sx; + mMatrix[0 * 4 + 1] *= sx; + mMatrix[0 * 4 + 2] *= sx; + mMatrix[0 * 4 + 3] *= sx; + + mMatrix[1 * 4 + 0] *= sy; + mMatrix[1 * 4 + 1] *= sy; + mMatrix[1 * 4 + 2] *= sy; + mMatrix[1 * 4 + 3] *= sy; + + mMatrix[2 * 4 + 0] *= sz; + mMatrix[2 * 4 + 1] *= sz; + mMatrix[2 * 4 + 2] *= sz; + mMatrix[2 * 4 + 3] *= sz; + } + + public void translate(float tx, float ty, float tz) { + mMatrix[3 * 4 + 0] += ( mMatrix[0 * 4 + 0] * tx + mMatrix[1 * 4 + 0] + * ty + mMatrix[2 * 4 + 0] * tz ); + mMatrix[3 * 4 + 1] += ( mMatrix[0 * 4 + 1] * tx + mMatrix[1 * 4 + 1] + * ty + mMatrix[2 * 4 + 1] * tz ); + mMatrix[3 * 4 + 2] += ( mMatrix[0 * 4 + 2] * tx + mMatrix[1 * 4 + 2] + * ty + mMatrix[2 * 4 + 2] * tz ); + mMatrix[3 * 4 + 3] += ( mMatrix[0 * 4 + 3] * tx + mMatrix[1 * 4 + 3] + * ty + mMatrix[2 * 4 + 3] * tz ); + } + + public void rotate (float angle, float x, float y, float z) { + float sinAngle, cosAngle; + float mag = (float) Math.sqrt ((double)(x * x + y * y + z * z)); + + sinAngle = (float) Math.sin ((double)(angle * Math.PI / 180.0)); + cosAngle = (float) Math.cos ((double)(angle * Math.PI / 180.0)); + + if ( mag > 0.0f ) { + float xx, yy, zz, xy, yz, zx, xs, ys, zs; + float oneMinusCos; + float[] rotMat = new float[16]; + + x /= mag; + y /= mag; + z /= mag; + + xx = x * x; + yy = y * y; + zz = z * z; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * sinAngle; + ys = y * sinAngle; + zs = z * sinAngle; + oneMinusCos = 1.0f - cosAngle; + + rotMat[0 * 4 + 0] = ( oneMinusCos * xx ) + cosAngle; + rotMat[0 * 4 + 1] = ( oneMinusCos * xy ) - zs; + rotMat[0 * 4 + 2] = ( oneMinusCos * zx ) + ys; + rotMat[0 * 4 + 3] = 0.0F; + + rotMat[1 * 4 + 0] = ( oneMinusCos * xy ) + zs; + rotMat[1 * 4 + 1] = ( oneMinusCos * yy ) + cosAngle; + rotMat[1 * 4 + 2] = ( oneMinusCos * yz ) - xs; + rotMat[1 * 4 + 3] = 0.0F; + + rotMat[2 * 4 + 0] = ( oneMinusCos * zx ) - ys; + rotMat[2 * 4 + 1] = ( oneMinusCos * yz ) + xs; + rotMat[2 * 4 + 2] = ( oneMinusCos * zz ) + cosAngle; + rotMat[2 * 4 + 3] = 0.0F; + + rotMat[3 * 4 + 0] = 0.0F; + rotMat[3 * 4 + 1] = 0.0F; + rotMat[3 * 4 + 2] = 0.0F; + rotMat[3 * 4 + 3] = 1.0F; + + matrixMultiply ( rotMat, mMatrix ); + } + } + + public void frustum (float left, float right, float bottom, float top, + float nearZ, float farZ) { + float deltaX = right - left; + float deltaY = top - bottom; + float deltaZ = farZ - nearZ; + float[] frust = new float[16]; + + if ((nearZ <= 0.0f) || (farZ <= 0.0f) || + (deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f)) { + return; + } + + frust[0 * 4 + 0] = 2.0f * nearZ / deltaX; + frust[0 * 4 + 1] = frust[0 * 4 + 2] = frust[0 * 4 + 3] = 0.0f; + + frust[1 * 4 + 1] = 2.0f * nearZ / deltaY; + frust[1 * 4 + 0] = frust[1 * 4 + 2] = frust[1 * 4 + 3] = 0.0f; + + frust[2 * 4 + 0] = ( right + left ) / deltaX; + frust[2 * 4 + 1] = ( top + bottom ) / deltaY; + frust[2 * 4 + 2] = - ( nearZ + farZ ) / deltaZ; + frust[2 * 4 + 3] = -1.0f; + + frust[3 * 4 + 2] = -2.0f * nearZ * farZ / deltaZ; + frust[3 * 4 + 0] = frust[3 * 4 + 1] = frust[3 * 4 + 3] = 0.0f; + + matrixMultiply ( frust, mMatrix ); + } + + public void perspective (float fovy, float aspect, float nearZ, float farZ) { + float frustumW, frustumH; + + frustumH = (float)Math.tan(fovy / 360.0 * Math.PI) * nearZ; + frustumW = frustumH * aspect; + + frustum (-frustumW, frustumW, -frustumH, frustumH, nearZ, farZ); + } + + public void ortho (float left, float right, float bottom, float top, + float nearZ, float farZ) { + float deltaX = right - left; + float deltaY = top - bottom; + float deltaZ = farZ - nearZ; + float[] orthoMat = makeIdentityMatrix(); + + if ((deltaX == 0.0f) || (deltaY == 0.0f) || (deltaZ == 0.0f)) { + return; + } + + orthoMat[0 * 4 + 0] = 2.0f / deltaX; + orthoMat[3 * 4 + 0] = - ( right + left ) / deltaX; + orthoMat[1 * 4 + 1] = 2.0f / deltaY; + orthoMat[3 * 4 + 1] = - ( top + bottom ) / deltaY; + orthoMat[2 * 4 + 2] = -2.0f / deltaZ; + orthoMat[3 * 4 + 2] = - ( nearZ + farZ ) / deltaZ; + + matrixMultiply (orthoMat, mMatrix); + } + + public void matrixMultiply (float[] srcA, float[] srcB) { + float[] tmp = new float[16]; + int i; + + for (i = 0; i < 4; i++) { + tmp[i * 4 + 0] = ( srcA[i * 4 + 0] * srcB[0 * 4 + 0] ) + + ( srcA[i * 4 + 1] * srcB[1 * 4 + 0] ) + + ( srcA[i * 4 + 2] * srcB[2 * 4 + 0] ) + + ( srcA[i * 4 + 3] * srcB[3 * 4 + 0] ); + + tmp[i * 4 + 1] = ( srcA[i * 4 + 0] * srcB[0 * 4 + 1] ) + + ( srcA[i * 4 + 1] * srcB[1 * 4 + 1] ) + + ( srcA[i * 4 + 2] * srcB[2 * 4 + 1] ) + + ( srcA[i * 4 + 3] * srcB[3 * 4 + 1] ); + + tmp[i * 4 + 2] = ( srcA[i * 4 + 0] * srcB[0 * 4 + 2] ) + + ( srcA[i * 4 + 1] * srcB[1 * 4 + 2] ) + + ( srcA[i * 4 + 2] * srcB[2 * 4 + 2] ) + + ( srcA[i * 4 + 3] * srcB[3 * 4 + 2] ); + + tmp[i * 4 + 3] = ( srcA[i * 4 + 0] * srcB[0 * 4 + 3] ) + + ( srcA[i * 4 + 1] * srcB[1 * 4 + 3] ) + + ( srcA[i * 4 + 2] * srcB[2 * 4 + 3] ) + + ( srcA[i * 4 + 3] * srcB[3 * 4 + 3] ); + } + + mMatrix = tmp; + } + + public void matrixLoadIdentity() { + for ( int i = 0; i < 16; i++ ) { + mMatrix[i] = 0.0f; + } + + mMatrix[0 * 4 + 0] = 1.0f; + mMatrix[1 * 4 + 1] = 1.0f; + mMatrix[2 * 4 + 2] = 1.0f; + mMatrix[3 * 4 + 3] = 1.0f; + } + + private float[] makeIdentityMatrix() { + float[] result = new float[16]; + + for ( int i = 0; i < 16; i++ ) { + result[i] = 0.0f; + } + + result[0 * 4 + 0] = 1.0f; + result[1 * 4 + 1] = 1.0f; + result[2 * 4 + 2] = 1.0f; + result[3 * 4 + 3] = 1.0f; + + return result; + } + + public FloatBuffer getAsFloatBuffer() { + mMatrixFloatBuffer.put ( mMatrix ).position ( 0 ); + return mMatrixFloatBuffer; + } + + public float[] get() { + return mMatrix; + } + + private float[] mMatrix = new float[16]; + private FloatBuffer mMatrixFloatBuffer; +} diff --git a/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/TextureWrapRenderer.java b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/TextureWrapRenderer.java new file mode 100644 index 0000000..9d2b8a8 --- /dev/null +++ b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/TextureWrapRenderer.java @@ -0,0 +1,196 @@ +package com.ly.avfoundation.avfoundation.gles; + +import android.opengl.GLES20; +import android.opengl.GLES30; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; + +public class TextureWrapRenderer { + private static final String TAG = "[TextureWrapRenderer]"; + + private static final String vShaderStr = + "#version 300 es \n" + + "uniform float u_offset; \n" + + "layout(location = 0) in vec4 a_position; \n" + + "layout(location = 1) in vec2 a_texCoord; \n" + + "out vec2 v_texCoord; \n" + + "void main() \n" + + "{ \n" + + " gl_Position = a_position; \n" + + " gl_Position.x += u_offset; \n" + + " v_texCoord = a_texCoord; \n" + + "} \n"; + + private static final String fShaderStr = + "#version 300 es \n" + + "precision mediump float; \n" + + "in vec2 v_texCoord; \n" + + "layout(location = 0) out vec4 outColor; \n" + + "uniform sampler2D s_texture; \n" + + "void main() \n" + + "{ \n" + + " outColor = texture( s_texture, v_texCoord ); \n" + + "} \n"; + + public TextureWrapRenderer() { + mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + mVertices.put(mVerticesData).position(0); + + mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2).order(ByteOrder.nativeOrder()).asShortBuffer(); + mIndices.put(mIndicesData).position(0); + + mProgranObject = GLUtil.createProgram(vShaderStr, fShaderStr); + + mSamplerLoc = GLES20.glGetUniformLocation(mProgranObject, "s_texture"); + + mOffsetLoc = GLES20.glGetUniformLocation(mProgranObject, "u_offset"); + + mTextureID = createTexture2D(); + + GLES20.glClearColor(1.0f, 1.0f, 1.0f, 0.0f); + } + + public void setScreenBounds(int x, int y, int width, int height) { + mWidth = width; + mHeight = height; + mOriginX = x; + mOriginY = y; + } + + public void draw() { + GLES20.glViewport(mOriginX, mOriginY, mWidth, mHeight); + + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + + GLES20.glUseProgram(mProgranObject); + + mVertices.position(0); + GLES20.glVertexAttribPointer(0, 4, GLES20.GL_FLOAT, false, 6 * 4, mVertices); + + mVertices.position(4); + GLES20.glVertexAttribPointer(1, 2, GLES20.GL_FLOAT, false, 6 * 4, mVertices); + + GLES20.glEnableVertexAttribArray(0); + GLES20.glEnableVertexAttribArray(1); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID); + + GLES20.glUniform1i(mSamplerLoc, 0); + + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); + GLES20.glUniform1f(mOffsetLoc, -0.7f); + GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices); + + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glUniform1f(mOffsetLoc, 0.0f); + GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices); + + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_MIRRORED_REPEAT); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_MIRRORED_REPEAT); + GLES20.glUniform1f(mOffsetLoc, 0.7f); + GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices); + + GLES20.glDisableVertexAttribArray(1); + GLES20.glDisableVertexAttribArray(0); + } + + /// + // Generate an RGB8 checkerboard image + // + private ByteBuffer genCheckImage ( int width, int height, int checkSize ) + { + int x, + y; + byte[] pixels = new byte[width * height * 3]; + + + for ( y = 0; y < height; y++ ) + for ( x = 0; x < width; x++ ) + { + byte rColor = 0; + byte bColor = 0; + + if ( ( x / checkSize ) % 2 == 0 ) + { + rColor = ( byte ) ( 127 * ( ( y / checkSize ) % 2 ) ); + bColor = ( byte ) ( 127 * ( 1 - ( ( y / checkSize ) % 2 ) ) ); + } + else + { + bColor = ( byte ) ( 127 * ( ( y / checkSize ) % 2 ) ); + rColor = ( byte ) ( 127 * ( 1 - ( ( y / checkSize ) % 2 ) ) ); + } + + pixels[ ( y * width + x ) * 3] = rColor; + pixels[ ( y * width + x ) * 3 + 1] = 0; + pixels[ ( y * width + x ) * 3 + 2] = bColor; + } + + ByteBuffer result = ByteBuffer.allocateDirect ( width * height * 3 ); + result.put ( pixels ).position ( 0 ); + return result; + } + + /// + // Create a 2D texture image + // + private int createTexture2D( ) + { + // Texture object handle + int[] textureId = new int[1]; + int width = 128, height = 128; + ByteBuffer pixels; + + pixels = genCheckImage ( width, height, 64 ); + + // Generate a texture object + GLES20.glGenTextures ( 1, textureId, 0 ); + + // Bind the texture object + GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textureId[0] ); + + // Load mipmap level 0 + GLES20.glTexImage2D ( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, width, height, + 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, pixels ); + + // Set the filtering mode + GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR ); + GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR ); + + return textureId[0]; + } + + private int mProgranObject; + private int mSamplerLoc; + private int mOffsetLoc; + private int mTextureID; + + private int mWidth; + private int mHeight; + private int mOriginX; + private int mOriginY; + + private FloatBuffer mVertices; + private ShortBuffer mIndices; + + private final float[] mVerticesData = { + -0.3f, 0.3f, 0.0f, 1.0f, // Position 0 + -1.0f, -1.0f, // TexCoord 0 + -0.3f, -0.3f, 0.0f, 1.0f, // Position 1 + -1.0f, 2.0f, // TexCoord 1 + 0.3f, -0.3f, 0.0f, 1.0f, // Position 2 + 2.0f, 2.0f, // TexCoord 2 + 0.3f, 0.3f, 0.0f, 1.0f, // Position 3 + 2.0f, -1.0f // TexCoord 3 + }; + + private final short[] mIndicesData = { + 0, 1, 2, 0, 2, 3 + }; +} diff --git a/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/TriangleProgram.java b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/TriangleProgram.java new file mode 100644 index 0000000..1a4dcb3 --- /dev/null +++ b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/gles/TriangleProgram.java @@ -0,0 +1,212 @@ +package com.ly.avfoundation.avfoundation.gles; + +import android.opengl.GLES20; +import android.os.SystemClock; +import android.util.Log; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; + +public class TriangleProgram { + private String TAG = GLUtil.TAG; + + private static final String kVertexShaderSource = + "#version 300 es \n" + + "uniform mat4 u_mvpMatrix; \n" + + "layout(location = 0) in vec4 a_position; \n" + + "layout(location = 1) in vec4 a_color; \n" + + "out vec4 v_color; \n" + + "void main() \n" + + "{ \n" + + " gl_Position = u_mvpMatrix * a_position; \n" + + " v_color = a_color; \n" + + "} \n"; + + private static final String kFragmentShaderSource = + "#version 300 es \n" + + "precision mediump float; \n" + + "in vec4 v_color; \n" + + "out vec4 o_fragColor; \n" + + "void main() \n" + + "{ \n" + + " o_fragColor = v_color; \n" + + "} \n"; + + private static final byte[] kPixels = { + (byte)255, 0, 0, + 0, (byte)255, 0, + 0, 0, (byte)255, + (byte)255, (byte)255, 0, + }; + + private FloatBuffer mVertices; + private FloatBuffer mColor; + private ByteBuffer mIndexs; + private ByteBuffer mPixels; + + private int mProgramHandler; + private int mPosition_X; + private int mPosition_Y; + private int mPosition_W; + private int mPosition_H; + + private int mLocationPosition; + private int mLocationColor; + private int mLocationMVPMatrix; + + private int mTextureID = -1; + + public TriangleProgram() { + mProgramHandler = GLUtil.createProgram(kVertexShaderSource, kFragmentShaderSource); + mVertices = null; + + mLocationPosition = GLES20.glGetAttribLocation(mProgramHandler, "a_position"); + mLocationColor = GLES20.glGetAttribLocation(mProgramHandler, "a_color"); + mLocationMVPMatrix = GLES20.glGetUniformLocation(mProgramHandler, "u_mvpMatrix"); + mPixels = ByteBuffer.allocateDirect(kPixels.length).order(ByteOrder.nativeOrder()).put(kPixels); + mPixels.position(0); + + int textures[] = new int[1]; + + GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); + + GLES20.glGenTextures(1, textures, 0); + mTextureID = textures[0]; + + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID); + + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, 2, 2, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, mPixels); + + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); + + Log.i(TAG, "TriangleProgram color:" + mLocationColor + " position:" + mLocationPosition); + } + + public void release() { + Log.d(TAG, "Triangle program release!!!"); + GLES20.glDeleteProgram(mProgramHandler); + mProgramHandler = -1; + } + + public void setScreenBounds(int x, int y, int w, int h) { + mPosition_X = x; + mPosition_Y = y; + mPosition_W = w; + mPosition_H = h; + } + + public void draw() { + float color[] = { 1.0f, 0.0f, 0.0f, 1.0f}; + byte indes[] = { + 0, 1, 3, 0, 2, 3, + 0, 1, 5, 0, 5, 4, + 0, 2, 6, 0, 6, 4, + 7, 5, 4, 7, 4, 6, + 7, 5, 1, 7, 1, 3, + 7, 3, 2, 7, 2, 6}; + float vertexPos[] = { + -0.5f, -0.5f, -0.5f, + 0.5f, -0.5f, -0.5f, + -0.5f, 0.5f, -0.5f, + 0.5f, 0.5f, -0.5f, + -0.5f, -0.5f, 0.5f, + 0.5f, -0.5f, 0.5f, + -0.5f, 0.5f, 0.5f, + 0.5f, 0.5f, 0.5f, + }; + + this.update(); + + mColor = this.arrayToFloatBuffer(color); + mVertices = this.arrayToFloatBuffer(vertexPos); + mIndexs = ByteBuffer.allocateDirect(indes.length).order(ByteOrder.nativeOrder()).put(indes); + mIndexs.position(0); + + GLES20.glEnable(GLES20.GL_DEPTH_TEST); + + GLES20.glViewport(mPosition_X, mPosition_Y, mPosition_W, mPosition_H); + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); + + GLES20.glUseProgram(mProgramHandler); + +// GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, mVertices); + GLES20.glVertexAttrib4fv(mLocationColor, mColor); + + GLES20.glVertexAttribPointer(mLocationPosition, 3, GLES20.GL_FLOAT, false, 0, mVertices); + GLES20.glEnableVertexAttribArray(mLocationPosition); + + GLES20.glUniformMatrix4fv(mLocationMVPMatrix, 1, false, mMVPMatrix.getAsFloatBuffer()); + +// GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + GLES20.glDrawElements(GLES20.GL_TRIANGLES, indes.length, GLES20.GL_UNSIGNED_BYTE, mIndexs); + + GLES20.glDisableVertexAttribArray(mLocationPosition); + } + + private FloatBuffer arrayToFloatBuffer(float vertex[]) { + ByteBuffer bb = ByteBuffer.allocateDirect(vertex.length * 4); + bb.order(ByteOrder.nativeOrder()); + + FloatBuffer floatBuffer = bb.asFloatBuffer(); + floatBuffer.put(vertex); + floatBuffer.position(0); + return floatBuffer; + } + + private ShortBuffer arrayToShortBuffer(short array[]) { + ByteBuffer bb = ByteBuffer.allocateDirect(array.length * 2); + bb.order(ByteOrder.nativeOrder()); + + ShortBuffer shortBuffer = bb.asShortBuffer(); + shortBuffer.put(array); + shortBuffer.position(0); + return shortBuffer; + } + + private void update() { + if (mLastTime == 0) + mLastTime = SystemClock.uptimeMillis(); + + long curTime = SystemClock.uptimeMillis(); + long elapsedTime = curTime - mLastTime; + double deltaTime = elapsedTime / 1000.0; + mLastTime = curTime; + + ESTransform perspective = new ESTransform(); + ESTransform modelView = new ESTransform(); + float aspect; + + mAngle += (deltaTime * 40.0f); + if (mAngle >= 360.0f) + mAngle -= 360.0f; + + aspect = (float) mPosition_W / (float) mPosition_H; + + perspective.matrixLoadIdentity(); + perspective.perspective(60.0f, aspect, 0.1f, 20.0f); + + modelView.matrixLoadIdentity(); + + modelView.translate(0.0f, 0.0f, -2.0f); + modelView.rotate(mAngle, 1.0f, 0.0f, 1.0f); + + mMVPMatrix.matrixMultiply(modelView.get(), perspective.get()); + } + + private int [] mVBOIds = new int[2]; + + private final int VERTEX_POS_SIZE = 3; + private final int VERTEX_COLOR_SIZE = 4; + + private final int VERTEX_POS_INDX = 0; + private final int VERTEX_COLOR_INDX = 1; + + private final int VERTEX_STRIDE = ( 4 * ( VERTEX_POS_SIZE + VERTEX_COLOR_SIZE ) ); + + private ESTransform mMVPMatrix = new ESTransform(); + private long mLastTime = 0; + private float mAngle = 90.0f; +} diff --git a/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/render/TriangleRender.java b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/render/TriangleRender.java new file mode 100644 index 0000000..e2f9650 --- /dev/null +++ b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/render/TriangleRender.java @@ -0,0 +1,40 @@ +package com.ly.avfoundation.avfoundation.render; + +import android.opengl.GLES20; +import android.opengl.GLSurfaceView; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import com.ly.avfoundation.avfoundation.gles.TextureWrapRenderer; +import com.ly.avfoundation.avfoundation.gles.TriangleProgram; + +import java.lang.ref.WeakReference; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +public class TriangleRender implements GLSurfaceView.Renderer { + private final static String TAG = "[TriangleRender]"; + private TextureWrapRenderer mProgramHandler; + + @Override + public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) { + GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + + mProgramHandler = new TextureWrapRenderer(); + Log.i(TAG, "onSurfaceCreated: " + eglConfig); + } + + @Override + public void onSurfaceChanged(GL10 gl10, int width, int height) { + Log.i(TAG, "onSurfaceChanged (" + width + "," + height + ");"); + mProgramHandler.setScreenBounds(0, 0, width, height); + } + + @Override + public void onDrawFrame(GL10 gl10) { + GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + mProgramHandler.draw(); + } +} diff --git a/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/render/TriangleRender2.java b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/render/TriangleRender2.java new file mode 100644 index 0000000..a551227 --- /dev/null +++ b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/avfoundation/render/TriangleRender2.java @@ -0,0 +1,143 @@ +package com.ly.avfoundation.avfoundation.render; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceHolder; + +import androidx.annotation.NonNull; + +import com.ly.avfoundation.avfoundation.gles.EglCore; +import com.ly.avfoundation.avfoundation.gles.TextureWrapRenderer; +import com.ly.avfoundation.avfoundation.gles.TriangleProgram; +import com.ly.avfoundation.avfoundation.gles.WindowSurface; + +import java.lang.ref.WeakReference; + +public class TriangleRender2 implements SurfaceHolder.Callback, Runnable { + public static final String TAG = "[TriangleRender2]"; + + private EglCore mEGLCore; + private WindowSurface mWindowSurface; + private TriangleProgram mProgram; + private Handler mHandler = null; + private Thread mThread = null; + private boolean mInitialized = false; + private boolean mQuit; + + public static final int MSG_SURFACE_CREATE = 0; + public static final int MSG_SURFACE_CHANGE = 1; + public static final int MSG_SURFACE_RENDER = 2; + public static final int MSG_SURFACE_DESTROY = 3; + + public static class Bounds { + public int format; + public int width; + public int height; + + public Bounds(int f, int w, int h) { + format = f; + width = w; + height = h; + } + + @NonNull + @Override + public String toString() { + return "Bounds:{width:" + width + " height:" + height + " format:" + format + "};"; + } + } + + public TriangleRender2() { + mThread = new Thread(this); + mHandler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SURFACE_CREATE: + handleSurfaceCreate((SurfaceHolder)msg.obj); + break; + case MSG_SURFACE_CHANGE: + handleSurfaceChange((Bounds)msg.obj); + break; + case MSG_SURFACE_RENDER: + handleSurfaceRende(); + break; + case MSG_SURFACE_DESTROY: + handleSurfaceDestroy(); + break; + } + return; + } + }; + } + + @Override + public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) { + mQuit = false; + mThread.start(); + mHandler.sendMessage(mHandler.obtainMessage(MSG_SURFACE_CREATE, surfaceHolder)); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int format, int width, int height) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_SURFACE_CHANGE, new Bounds(format, width, height))); + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) { + mQuit = true; + mHandler.sendMessage(mHandler.obtainMessage(MSG_SURFACE_DESTROY)); + try { + mThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Override + public void run() { + // onDrawFrame + while (!mQuit) { + Log.i(TAG, "run: " + mQuit); + mHandler.sendMessage(mHandler.obtainMessage(MSG_SURFACE_RENDER)); + } + } + + public void handleSurfaceCreate(SurfaceHolder surfaceHolder) { + mEGLCore = new EglCore(); + mWindowSurface = new WindowSurface(mEGLCore, surfaceHolder.getSurface(), false); + + mWindowSurface.makeCurrent(); + mProgram = new TriangleProgram(); + Log.i(TAG, "handleSurfaceCreate " + mWindowSurface); + } + + public void handleSurfaceChange(Bounds bounds) { + if (mProgram != null) { + mProgram.setScreenBounds(0, 0, bounds.width, bounds.height); + } + Log.i(TAG, "handleSurfaceChange " + bounds); + } + + public void handleSurfaceRende() { + mWindowSurface.makeCurrent(); + if (mProgram != null) { + mProgram.draw(); + } + mWindowSurface.swapBuffers(); + } + + public void handleSurfaceDestroy() { + mProgram = null; + if (mWindowSurface != null) { + mWindowSurface.release(); + } + if (mEGLCore != null) { + mEGLCore.release(); + } + Log.i(TAG, "handleSurfaceDestroy"); + } +} diff --git a/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/fragment/OpenGLESFragment.java b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/fragment/OpenGLESFragment.java new file mode 100644 index 0000000..df47750 --- /dev/null +++ b/project/android/AVFoundation/app/src/main/java/com/ly/avfoundation/fragment/OpenGLESFragment.java @@ -0,0 +1,40 @@ +package com.ly.avfoundation.fragment; + +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.opengl.GLSurfaceView; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; + +import androidx.fragment.app.Fragment; + +import com.ly.avfoundation.R; +import com.ly.avfoundation.avfoundation.render.TriangleRender; +import com.ly.avfoundation.avfoundation.render.TriangleRender2; + +public class OpenGLESFragment extends Fragment { + private TriangleRender mRender; + private TriangleRender2 mRender2; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.opengles_fragment, group, false); + + SurfaceView surfaceView = view.findViewById(R.id.surfaceView2); + mRender2 = new TriangleRender2(); + surfaceView.getHolder().addCallback(mRender2); + surfaceView.setZOrderOnTop(true); + surfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT); + return view; + } + + public static OpenGLESFragment newInstance(Bundle saveInstanceState) { + OpenGLESFragment fragment = new OpenGLESFragment(); + Bundle bundle = new Bundle(); + fragment.setArguments(bundle); + return fragment; + } +} diff --git a/project/android/AVFoundation/app/src/main/res/layout/opengles_fragment.xml b/project/android/AVFoundation/app/src/main/res/layout/opengles_fragment.xml new file mode 100644 index 0000000..e2e231b --- /dev/null +++ b/project/android/AVFoundation/app/src/main/res/layout/opengles_fragment.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file -- GitLab