/* * 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 jp.co.cyberagent.android.gpuimage; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil; import android.graphics.Bitmap; import android.opengl.GLES20; public class GPUImageTwoInputFilter extends GPUImageFilter { private static final String VERTEX_SHADER = "attribute vec4 position;\n" + "attribute vec4 inputTextureCoordinate;\n" + "attribute vec4 inputTextureCoordinate2;\n" + " \n" + "varying vec2 textureCoordinate;\n" + "varying vec2 textureCoordinate2;\n" + " \n" + "void main()\n" + "{\n" + " gl_Position = position;\n" + " textureCoordinate = inputTextureCoordinate.xy;\n" + " textureCoordinate2 = inputTextureCoordinate2.xy;\n" + "}"; public int mFilterSecondTextureCoordinateAttribute; public int mFilterInputTextureUniform2; public int mFilterSourceTexture2 = OpenGlUtils.NO_TEXTURE; private ByteBuffer mTexture2CoordinatesBuffer; private Bitmap mBitmap; public GPUImageTwoInputFilter(String fragmentShader) { this(VERTEX_SHADER, fragmentShader); } public GPUImageTwoInputFilter(String vertexShader, String fragmentShader) { super(vertexShader, fragmentShader); setRotation(Rotation.NORMAL, false, false); } @Override public void onInit() { super.onInit(); mFilterSecondTextureCoordinateAttribute = GLES20.glGetAttribLocation(getProgram(), "inputTextureCoordinate2"); mFilterInputTextureUniform2 = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture2"); // This does assume a name of "inputImageTexture2" for second input texture in the fragment shader GLES20.glEnableVertexAttribArray(mFilterSecondTextureCoordinateAttribute); if (mBitmap != null&&!mBitmap.isRecycled()) { setBitmap(mBitmap); } } public void setBitmap(final Bitmap bitmap) { if (bitmap != null && bitmap.isRecycled()) { return; } mBitmap = bitmap; if (mBitmap == null) { return; } runOnDraw(new Runnable() { @Override public void run() { if (mFilterSourceTexture2 == OpenGlUtils.NO_TEXTURE) { if (bitmap == null || bitmap.isRecycled()) { return; } GLES20.glActiveTexture(GLES20.GL_TEXTURE3); mFilterSourceTexture2 = OpenGlUtils.loadTexture(bitmap, OpenGlUtils.NO_TEXTURE, false); } } }); } public Bitmap getBitmap() { return mBitmap; } public void recycleBitmap() { if (mBitmap != null && !mBitmap.isRecycled()) { mBitmap.recycle(); mBitmap = null; } } @Override public void onDestroy() { super.onDestroy(); GLES20.glDeleteTextures(1, new int[]{ mFilterSourceTexture2 }, 0); mFilterSourceTexture2 = OpenGlUtils.NO_TEXTURE; } @Override protected void onDrawArraysPre() { GLES20.glEnableVertexAttribArray(mFilterSecondTextureCoordinateAttribute); GLES20.glActiveTexture(GLES20.GL_TEXTURE3); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mFilterSourceTexture2); GLES20.glUniform1i(mFilterInputTextureUniform2, 3); mTexture2CoordinatesBuffer.position(0); GLES20.glVertexAttribPointer(mFilterSecondTextureCoordinateAttribute, 2, GLES20.GL_FLOAT, false, 0, mTexture2CoordinatesBuffer); } public void setRotation(final Rotation rotation, final boolean flipHorizontal, final boolean flipVertical) { float[] buffer = TextureRotationUtil.getRotation(rotation, flipHorizontal, flipVertical); ByteBuffer bBuffer = ByteBuffer.allocateDirect(32).order(ByteOrder.nativeOrder()); FloatBuffer fBuffer = bBuffer.asFloatBuffer(); fBuffer.put(buffer); fBuffer.flip(); mTexture2CoordinatesBuffer = bBuffer; } }