Skip to content
Snippets Groups Projects
Commit c2a93b6b authored by Leo Ma's avatar Leo Ma
Browse files

Simplify GLES vertex setting


Signed-off-by: default avatarLeo Ma <begeekmyfriend@gmail.com>
parent c03254ae
No related branches found
No related tags found
No related merge requests found
/*
* Copyright (C) 2012 CyberAgent
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seu.magicfilter.base.gpuimage;
import android.content.Context;
import android.graphics.PointF;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import com.seu.magicfilter.utils.MagicFilterType;
import com.seu.magicfilter.utils.OpenGLUtils;
import net.ossrs.yasea.R;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.LinkedList;
public class GPUImageFilter {
private boolean mIsInitialized;
private Context mContext;
private MagicFilterType mType = MagicFilterType.NONE;
private final LinkedList<Runnable> mRunOnDraw;
private final int mVertexShaderId;
private final int mFragmentShaderId;
private int mGLProgId;
private int mGLPositionIndex;
private int mGLInputImageTextureIndex;
private int mGLTextureCoordinateIndex;
private int mGLTextureTransformIndex;
protected int mInputWidth;
protected int mInputHeight;
protected int mOutputWidth;
protected int mOutputHeight;
protected FloatBuffer mGLCubeBuffer;
protected FloatBuffer mGLTextureBuffer;
private int[] mGLCubeId;
private int[] mGLTextureCoordinateId;
private float[] mGLTextureTransformMatrix;
private int[] mGLFboId;
private int[] mGLFboTexId;
private IntBuffer mGLFboBuffer;
public GPUImageFilter() {
this(MagicFilterType.NONE);
}
public GPUImageFilter(MagicFilterType type) {
this(type, R.raw.vertex, R.raw.fragment);
}
public GPUImageFilter(MagicFilterType type, int fragmentShaderId) {
this(type, R.raw.vertex, fragmentShaderId);
}
public GPUImageFilter(MagicFilterType type, int vertexShaderId, int fragmentShaderId) {
mType = type;
mRunOnDraw = new LinkedList<>();
mVertexShaderId = vertexShaderId;
mFragmentShaderId = fragmentShaderId;
}
public void init(Context context) {
mContext = context;
onInit();
onInitialized();
}
protected void onInit() {
initVbo();
loadSamplerShader();
}
protected void onInitialized() {
mIsInitialized = true;
}
public final void destroy() {
mIsInitialized = false;
destroyFboTexture();
destoryVbo();
GLES20.glDeleteProgram(mGLProgId);
onDestroy();
}
protected void onDestroy() {
}
public void onInputSizeChanged(final int width, final int height) {
mInputWidth = width;
mInputHeight = height;
initFboTexture(width, height);
}
public void onDisplaySizeChanged(final int width, final int height) {
mOutputWidth = width;
mOutputHeight = height;
}
private void loadSamplerShader() {
mGLProgId = OpenGLUtils.loadProgram(OpenGLUtils.readShaderFromRawResource(getContext(), mVertexShaderId),
OpenGLUtils.readShaderFromRawResource(getContext(), mFragmentShaderId));
mGLPositionIndex = GLES20.glGetAttribLocation(mGLProgId, "position");
mGLTextureCoordinateIndex = GLES20.glGetAttribLocation(mGLProgId,"inputTextureCoordinate");
mGLTextureTransformIndex = GLES20.glGetUniformLocation(mGLProgId, "textureTransform");
mGLInputImageTextureIndex = GLES20.glGetUniformLocation(mGLProgId, "inputImageTexture");
}
private void initVbo() {
final float VEX_CUBE[] = {
-1.0f, -1.0f, // Bottom left.
1.0f, -1.0f, // Bottom right.
-1.0f, 1.0f, // Top left.
1.0f, 1.0f, // Top right.
};
final float TEX_COORD[] = {
0.0f, 0.0f, // Bottom left.
1.0f, 0.0f, // Bottom right.
0.0f, 1.0f, // Top left.
1.0f, 1.0f // Top right.
};
mGLCubeBuffer = ByteBuffer.allocateDirect(VEX_CUBE.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mGLCubeBuffer.put(VEX_CUBE).position(0);
mGLTextureBuffer = ByteBuffer.allocateDirect(TEX_COORD.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mGLTextureBuffer.put(TEX_COORD).position(0);
mGLCubeId = new int[1];
mGLTextureCoordinateId = new int[1];
GLES20.glGenBuffers(1, mGLCubeId, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLCubeId[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mGLCubeBuffer.capacity() * 4, mGLCubeBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glGenBuffers(1, mGLTextureCoordinateId, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLTextureCoordinateId[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mGLTextureBuffer.capacity() * 4, mGLTextureBuffer, GLES20.GL_STATIC_DRAW);
}
private void destoryVbo() {
if (mGLCubeId != null) {
GLES20.glDeleteBuffers(1, mGLCubeId, 0);
mGLCubeId = null;
}
if (mGLTextureCoordinateId != null) {
GLES20.glDeleteBuffers(1, mGLTextureCoordinateId, 0);
mGLTextureCoordinateId = null;
}
}
private void initFboTexture(int width, int height) {
if (mGLFboId != null && (mInputWidth != width || mInputHeight != height)) {
destroyFboTexture();
}
mGLFboId = new int[1];
mGLFboTexId = new int[1];
mGLFboBuffer = IntBuffer.allocate(width * height);
GLES20.glGenFramebuffers(1, mGLFboId, 0);
GLES20.glGenTextures(1, mGLFboTexId, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mGLFboTexId[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mGLFboId[0]);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, mGLFboTexId[0], 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
}
private void destroyFboTexture() {
if (mGLFboTexId != null) {
GLES20.glDeleteTextures(1, mGLFboTexId, 0);
mGLFboTexId = null;
}
if (mGLFboId != null) {
GLES20.glDeleteFramebuffers(1, mGLFboId, 0);
mGLFboId = null;
}
}
public int onDrawFrame(final int textureId, final FloatBuffer cubeBuffer, final FloatBuffer textureBuffer) {
if (!mIsInitialized) {
return OpenGLUtils.NOT_INIT;
}
GLES20.glUseProgram(mGLProgId);
runPendingOnDrawTasks();
GLES20.glEnableVertexAttribArray(mGLPositionIndex);
GLES20.glVertexAttribPointer(mGLPositionIndex, 2, GLES20.GL_FLOAT, false, 4 * 2, cubeBuffer);
GLES20.glEnableVertexAttribArray(mGLTextureCoordinateIndex);
GLES20.glVertexAttribPointer(mGLTextureCoordinateIndex, 2, GLES20.GL_FLOAT, false, 4 * 2, textureBuffer);
if (textureId != OpenGLUtils.NO_TEXTURE) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLES20.glUniform1i(mGLInputImageTextureIndex, 0);
}
onDrawArraysPre();
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
onDrawArraysAfter();
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glDisableVertexAttribArray(mGLPositionIndex);
GLES20.glDisableVertexAttribArray(mGLTextureCoordinateIndex);
return OpenGLUtils.ON_DRAWN;
}
public int onDrawFrame(int cameraTextureId) {
if (!mIsInitialized) {
return OpenGLUtils.NOT_INIT;
}
if (mGLFboId == null) {
return OpenGLUtils.NO_TEXTURE;
}
GLES20.glUseProgram(mGLProgId);
runPendingOnDrawTasks();
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLCubeId[0]);
GLES20.glEnableVertexAttribArray(mGLPositionIndex);
GLES20.glVertexAttribPointer(mGLPositionIndex, 2, GLES20.GL_FLOAT, false, 4 * 2, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLTextureCoordinateId[0]);
GLES20.glEnableVertexAttribArray(mGLTextureCoordinateIndex);
GLES20.glVertexAttribPointer(mGLTextureCoordinateIndex, 2, GLES20.GL_FLOAT, false, 4 * 2, 0);
GLES20.glUniformMatrix4fv(mGLTextureTransformIndex, 1, false, mGLTextureTransformMatrix, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTextureId);
GLES20.glUniform1i(mGLInputImageTextureIndex, 0);
onDrawArraysPre();
GLES20.glViewport(0, 0, mInputWidth, mInputHeight);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mGLFboId[0]);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glReadPixels(0, 0, mInputWidth, mInputHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mGLFboBuffer);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glViewport(0, 0, mOutputWidth, mOutputHeight);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
onDrawArraysAfter();
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
GLES20.glDisableVertexAttribArray(mGLPositionIndex);
GLES20.glDisableVertexAttribArray(mGLTextureCoordinateIndex);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
return mGLFboTexId[0];
}
protected void onDrawArraysPre() {}
protected void onDrawArraysAfter() {}
private void runPendingOnDrawTasks() {
while (!mRunOnDraw.isEmpty()) {
mRunOnDraw.removeFirst().run();
}
}
public int getProgram() {
return mGLProgId;
}
public IntBuffer getGLFboBuffer() {
return mGLFboBuffer;
}
protected Context getContext() {
return mContext;
}
protected MagicFilterType getFilterType() {
return mType;
}
public void setTextureTransformMatrix(float[] mtx){
mGLTextureTransformMatrix = mtx;
}
protected void setInteger(final int location, final int intValue) {
runOnDraw(new Runnable() {
@Override
public void run() {
GLES20.glUniform1i(location, intValue);
}
});
}
protected void setFloat(final int location, final float floatValue) {
runOnDraw(new Runnable() {
@Override
public void run() {
GLES20.glUniform1f(location, floatValue);
}
});
}
protected void setFloatVec2(final int location, final float[] arrayValue) {
runOnDraw(new Runnable() {
@Override
public void run() {
GLES20.glUniform2fv(location, 1, FloatBuffer.wrap(arrayValue));
}
});
}
protected void setFloatVec3(final int location, final float[] arrayValue) {
runOnDraw(new Runnable() {
@Override
public void run() {
GLES20.glUniform3fv(location, 1, FloatBuffer.wrap(arrayValue));
}
});
}
protected void setFloatVec4(final int location, final float[] arrayValue) {
runOnDraw(new Runnable() {
@Override
public void run() {
GLES20.glUniform4fv(location, 1, FloatBuffer.wrap(arrayValue));
}
});
}
protected void setFloatArray(final int location, final float[] arrayValue) {
runOnDraw(new Runnable() {
@Override
public void run() {
GLES20.glUniform1fv(location, arrayValue.length, FloatBuffer.wrap(arrayValue));
}
});
}
protected void setPoint(final int location, final PointF point) {
runOnDraw(new Runnable() {
@Override
public void run() {
float[] vec2 = new float[2];
vec2[0] = point.x;
vec2[1] = point.y;
GLES20.glUniform2fv(location, 1, vec2, 0);
}
});
}
protected void setUniformMatrix3f(final int location, final float[] matrix) {
runOnDraw(new Runnable() {
@Override
public void run() {
GLES20.glUniformMatrix3fv(location, 1, false, matrix, 0);
}
});
}
protected void setUniformMatrix4f(final int location, final float[] matrix) {
runOnDraw(new Runnable() {
@Override
public void run() {
GLES20.glUniformMatrix4fv(location, 1, false, matrix, 0);
}
});
}
protected void runOnDraw(final Runnable runnable) {
synchronized (mRunOnDraw) {
mRunOnDraw.addLast(runnable);
}
}
}
/*
* Copyright (C) 2012 CyberAgent
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seu.magicfilter.utils;
public enum Rotation {
NORMAL, ROTATION_90, ROTATION_180, ROTATION_270;
/**
* Retrieves the int representation of the Rotation.
*
* @return 0, 90, 180 or 270
*/
public int asInt() {
switch (this) {
case NORMAL: return 0;
case ROTATION_90: return 90;
case ROTATION_180: return 180;
case ROTATION_270: return 270;
default: throw new IllegalStateException("Unknown Rotation!");
}
}
/**
* Create a Rotation from an integer. Needs to be either 0, 90, 180 or 270.
*
* @param rotation 0, 90, 180 or 270
* @return Rotation object
*/
public static Rotation fromInt(int rotation) {
switch (rotation) {
case 0: return NORMAL;
case 90: return ROTATION_90;
case 180: return ROTATION_180;
case 270: return ROTATION_270;
case 360: return NORMAL;
default: throw new IllegalStateException(
rotation + " is an unknown rotation. Needs to be either 0, 90, 180 or 270!");
}
}
}
/*
* Copyright (C) 2012 CyberAgent
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.seu.magicfilter.utils;
public class TextureRotationUtil {
public static final float TEXTURE_NO_ROTATION[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
public static final float TEXTURE_ROTATED_90[] = {
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
0.0f, 0.0f,
};
public static final float TEXTURE_ROTATED_180[] = {
1.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
};
public static final float TEXTURE_ROTATED_270[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f,
};
public static final float CUBE[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
private TextureRotationUtil() {}
public static float[] getRotation(final Rotation rotation, final boolean flipHorizontal,
final boolean flipVertical) {
float[] rotatedTex;
switch (rotation) {
case ROTATION_90:
rotatedTex = TEXTURE_ROTATED_90;
break;
case ROTATION_180:
rotatedTex = TEXTURE_ROTATED_180;
break;
case ROTATION_270:
rotatedTex = TEXTURE_ROTATED_270;
break;
case NORMAL:
default:
rotatedTex = TEXTURE_NO_ROTATION;
break;
}
if (flipHorizontal) {
rotatedTex = new float[]{
flip(rotatedTex[0]), rotatedTex[1],
flip(rotatedTex[2]), rotatedTex[3],
flip(rotatedTex[4]), rotatedTex[5],
flip(rotatedTex[6]), rotatedTex[7],
};
}
if (flipVertical) {
rotatedTex = new float[]{
rotatedTex[0], flip(rotatedTex[1]),
rotatedTex[2], flip(rotatedTex[3]),
rotatedTex[4], flip(rotatedTex[5]),
rotatedTex[6], flip(rotatedTex[7]),
};
}
return rotatedTex;
}
private static float flip(final float i) {
return i == 0.0f ? 1.0f : 0.0f;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment