mirror of https://github.com/NekoX-Dev/NekoX.git
718 lines
32 KiB
Java
718 lines
32 KiB
Java
/*
|
|
* This is the source code of Telegram for Android v. 6.x.x.
|
|
* It is licensed under GNU GPL v. 2 or later.
|
|
* You should have received a copy of the license in this archive (see LICENSE).
|
|
*
|
|
* Copyright Nikolai Kudashov, 2013-2020.
|
|
*/
|
|
|
|
package org.telegram.messenger.video;
|
|
|
|
import java.io.File;
|
|
import java.io.RandomAccessFile;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.nio.FloatBuffer;
|
|
import java.nio.channels.FileChannel;
|
|
import java.util.ArrayList;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.BitmapFactory;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.Paint;
|
|
import android.graphics.SurfaceTexture;
|
|
import android.graphics.Typeface;
|
|
import android.opengl.GLES11Ext;
|
|
import android.opengl.GLES20;
|
|
import android.opengl.GLUtils;
|
|
import android.opengl.Matrix;
|
|
import android.os.Build;
|
|
import android.text.Layout;
|
|
import android.util.TypedValue;
|
|
import android.view.Gravity;
|
|
import android.view.View;
|
|
import android.view.inputmethod.EditorInfo;
|
|
|
|
import org.telegram.messenger.AndroidUtilities;
|
|
import org.telegram.messenger.ApplicationLoader;
|
|
import org.telegram.messenger.Bitmaps;
|
|
import org.telegram.messenger.BuildVars;
|
|
import org.telegram.messenger.FileLog;
|
|
import org.telegram.messenger.MediaController;
|
|
import org.telegram.messenger.Utilities;
|
|
import org.telegram.messenger.VideoEditedInfo;
|
|
import org.telegram.ui.Components.FilterShaders;
|
|
import org.telegram.ui.Components.Paint.Views.EditTextOutline;
|
|
import org.telegram.ui.Components.RLottieDrawable;
|
|
|
|
import javax.microedition.khronos.opengles.GL10;
|
|
|
|
import androidx.annotation.RequiresApi;
|
|
import androidx.exifinterface.media.ExifInterface;
|
|
|
|
public class TextureRenderer {
|
|
|
|
private FloatBuffer verticesBuffer;
|
|
private FloatBuffer textureBuffer;
|
|
private FloatBuffer renderTextureBuffer;
|
|
private FloatBuffer bitmapVerticesBuffer;
|
|
|
|
float[] bitmapData = {
|
|
-1.0f, 1.0f,
|
|
1.0f, 1.0f,
|
|
-1.0f, -1.0f,
|
|
1.0f, -1.0f,
|
|
};
|
|
|
|
private FilterShaders filterShaders;
|
|
private String paintPath;
|
|
private String imagePath;
|
|
private ArrayList<VideoEditedInfo.MediaEntity> mediaEntities;
|
|
private int originalWidth;
|
|
private int originalHeight;
|
|
private int transformedWidth;
|
|
private int transformedHeight;
|
|
|
|
private static final String VERTEX_SHADER =
|
|
"uniform mat4 uMVPMatrix;\n" +
|
|
"uniform mat4 uSTMatrix;\n" +
|
|
"attribute vec4 aPosition;\n" +
|
|
"attribute vec4 aTextureCoord;\n" +
|
|
"varying vec2 vTextureCoord;\n" +
|
|
"void main() {\n" +
|
|
" gl_Position = uMVPMatrix * aPosition;\n" +
|
|
" vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
|
|
"}\n";
|
|
|
|
private static final String FRAGMENT_EXTERNAL_SHADER =
|
|
"#extension GL_OES_EGL_image_external : require\n" +
|
|
"precision highp float;\n" +
|
|
"varying vec2 vTextureCoord;\n" +
|
|
"uniform samplerExternalOES sTexture;\n" +
|
|
"void main() {\n" +
|
|
" gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
|
|
"}\n";
|
|
|
|
private static final String FRAGMENT_SHADER =
|
|
"precision highp float;\n" +
|
|
"varying vec2 vTextureCoord;\n" +
|
|
"uniform sampler2D sTexture;\n" +
|
|
"void main() {\n" +
|
|
" gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
|
|
"}\n";
|
|
|
|
private float[] mMVPMatrix = new float[16];
|
|
private float[] mSTMatrix = new float[16];
|
|
private float[] mSTMatrixIdentity = new float[16];
|
|
private int mTextureID;
|
|
private int[] mProgram;
|
|
private int[] muMVPMatrixHandle;
|
|
private int[] muSTMatrixHandle;
|
|
private int[] maPositionHandle;
|
|
private int[] maTextureHandle;
|
|
|
|
private int simpleShaderProgram;
|
|
private int simplePositionHandle;
|
|
private int simpleInputTexCoordHandle;
|
|
private int simpleSourceImageHandle;
|
|
|
|
private int[] paintTexture;
|
|
private int[] stickerTexture;
|
|
private Bitmap stickerBitmap;
|
|
private float videoFps;
|
|
|
|
private int imageOrientation;
|
|
|
|
private boolean blendEnabled;
|
|
|
|
private boolean isPhoto;
|
|
|
|
private boolean firstFrame = true;
|
|
|
|
public TextureRenderer(MediaController.SavedFilterState savedFilterState, String image, String paint, ArrayList<VideoEditedInfo.MediaEntity> entities, MediaController.CropState cropState, int w, int h, int rotation, float fps, boolean photo) {
|
|
isPhoto = photo;
|
|
|
|
float[] texData = {
|
|
0.f, 0.f,
|
|
1.f, 0.f,
|
|
0.f, 1.f,
|
|
1.f, 1.f,
|
|
};
|
|
|
|
if (BuildVars.LOGS_ENABLED) {
|
|
FileLog.d("start textureRenderer w = " + w + " h = " + h + " r = " + rotation + " fps = " + fps);
|
|
if (cropState != null) {
|
|
FileLog.d("cropState px = " + cropState.cropPx + " py = " + cropState.cropPy + " cScale = " + cropState.cropScale +
|
|
" cropRotate = " + cropState.cropRotate + " pw = " + cropState.cropPw + " ph = " + cropState.cropPh +
|
|
" tw = " + cropState.transformWidth + " th = " + cropState.transformHeight + " tr = " + cropState.transformRotation +
|
|
" mirror = " + cropState.mirrored);
|
|
}
|
|
}
|
|
|
|
textureBuffer = ByteBuffer.allocateDirect(texData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
|
textureBuffer.put(texData).position(0);
|
|
|
|
bitmapVerticesBuffer = ByteBuffer.allocateDirect(bitmapData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
|
bitmapVerticesBuffer.put(bitmapData).position(0);
|
|
|
|
Matrix.setIdentityM(mSTMatrix, 0);
|
|
Matrix.setIdentityM(mSTMatrixIdentity, 0);
|
|
|
|
if (savedFilterState != null) {
|
|
filterShaders = new FilterShaders(true);
|
|
filterShaders.setDelegate(FilterShaders.getFilterShadersDelegate(savedFilterState));
|
|
}
|
|
transformedWidth = originalWidth = w;
|
|
transformedHeight = originalHeight = h;
|
|
imagePath = image;
|
|
paintPath = paint;
|
|
mediaEntities = entities;
|
|
videoFps = fps == 0 ? 30 : fps;
|
|
|
|
int count;
|
|
if (filterShaders != null) {
|
|
count = 2;
|
|
} else {
|
|
count = 1;
|
|
}
|
|
mProgram = new int[count];
|
|
muMVPMatrixHandle = new int[count];
|
|
muSTMatrixHandle = new int[count];
|
|
maPositionHandle = new int[count];
|
|
maTextureHandle = new int[count];
|
|
|
|
Matrix.setIdentityM(mMVPMatrix, 0);
|
|
int textureRotation = 0;
|
|
if (cropState != null) {
|
|
float[] verticesData = {
|
|
0, 0,
|
|
w, 0,
|
|
0, h,
|
|
w, h,
|
|
};
|
|
textureRotation = cropState.transformRotation;
|
|
if (textureRotation == 90 || textureRotation == 270) {
|
|
int temp = originalWidth;
|
|
originalWidth = originalHeight;
|
|
originalHeight = temp;
|
|
}
|
|
|
|
transformedWidth *= cropState.cropPw;
|
|
transformedHeight *= cropState.cropPh;
|
|
|
|
float angle = (float) (-cropState.cropRotate * (Math.PI / 180.0f));
|
|
for (int a = 0; a < 4; a++) {
|
|
float x1 = verticesData[a * 2] - w / 2;
|
|
float y1 = verticesData[a * 2 + 1] - h / 2;
|
|
float x2 = (float) (x1 * Math.cos(angle) - y1 * Math.sin(angle) + cropState.cropPx * w) * cropState.cropScale;
|
|
float y2 = (float) (x1 * Math.sin(angle) + y1 * Math.cos(angle) - cropState.cropPy * h) * cropState.cropScale;
|
|
verticesData[a * 2] = x2 / transformedWidth * 2;
|
|
verticesData[a * 2 + 1] = y2 / transformedHeight * 2;
|
|
}
|
|
verticesBuffer = ByteBuffer.allocateDirect(verticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
|
verticesBuffer.put(verticesData).position(0);
|
|
} else {
|
|
float[] verticesData = {
|
|
-1.0f, -1.0f,
|
|
1.0f, -1.0f,
|
|
-1.0f, 1.0f,
|
|
1.0f, 1.0f,
|
|
};
|
|
verticesBuffer = ByteBuffer.allocateDirect(verticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
|
verticesBuffer.put(verticesData).position(0);
|
|
}
|
|
float[] textureData;
|
|
if (filterShaders != null) {
|
|
if (textureRotation == 90) {
|
|
textureData = new float[]{
|
|
1.f, 1.f,
|
|
1.f, 0.f,
|
|
0.f, 1.f,
|
|
0.f, 0.f
|
|
};
|
|
} else if (textureRotation == 180) {
|
|
textureData = new float[]{
|
|
1.f, 0.f,
|
|
0.f, 0.f,
|
|
1.f, 1.f,
|
|
0.f, 1.f
|
|
};
|
|
} else if (textureRotation == 270) {
|
|
textureData = new float[]{
|
|
0.f, 0.f,
|
|
0.f, 1.f,
|
|
1.f, 0.f,
|
|
1.f, 1.f
|
|
};
|
|
} else {
|
|
textureData = new float[]{
|
|
0.f, 1.f,
|
|
1.f, 1.f,
|
|
0.f, 0.f,
|
|
1.f, 0.f
|
|
};
|
|
}
|
|
} else {
|
|
if (textureRotation == 90) {
|
|
textureData = new float[]{
|
|
1.f, 0.f,
|
|
1.f, 1.f,
|
|
0.f, 0.f,
|
|
0.f, 1.f
|
|
};
|
|
} else if (textureRotation == 180) {
|
|
textureData = new float[]{
|
|
1.f, 1.f,
|
|
0.f, 1.f,
|
|
1.f, 0.f,
|
|
0.f, 0.f
|
|
};
|
|
} else if (textureRotation == 270) {
|
|
textureData = new float[]{
|
|
0.f, 1.f,
|
|
0.f, 0.f,
|
|
1.f, 1.f,
|
|
1.f, 0.f
|
|
};
|
|
} else {
|
|
textureData = new float[]{
|
|
0.f, 0.f,
|
|
1.f, 0.f,
|
|
0.f, 1.f,
|
|
1.f, 1.f
|
|
};
|
|
}
|
|
}
|
|
if (cropState != null && cropState.mirrored) {
|
|
for (int a = 0; a < 4; a++) {
|
|
if (textureData[a * 2] > 0.5f) {
|
|
textureData[a * 2] = 0.0f;
|
|
} else {
|
|
textureData[a * 2] = 1.0f;
|
|
}
|
|
}
|
|
}
|
|
renderTextureBuffer = ByteBuffer.allocateDirect(textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
|
renderTextureBuffer.put(textureData).position(0);
|
|
}
|
|
|
|
public int getTextureId() {
|
|
return mTextureID;
|
|
}
|
|
|
|
public void drawFrame(SurfaceTexture st) {
|
|
if (isPhoto) {
|
|
GLES20.glUseProgram(simpleShaderProgram);
|
|
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
|
|
|
GLES20.glUniform1i(simpleSourceImageHandle, 0);
|
|
GLES20.glEnableVertexAttribArray(simpleInputTexCoordHandle);
|
|
GLES20.glVertexAttribPointer(simpleInputTexCoordHandle, 2, GLES20.GL_FLOAT, false, 8, textureBuffer);
|
|
GLES20.glEnableVertexAttribArray(simplePositionHandle);
|
|
} else {
|
|
st.getTransformMatrix(mSTMatrix);
|
|
if (BuildVars.LOGS_ENABLED && firstFrame) {
|
|
StringBuilder builder = new StringBuilder();
|
|
for (int a = 0; a < mSTMatrix.length; a++) {
|
|
builder.append(mSTMatrix[a]).append(", ");
|
|
}
|
|
FileLog.d("stMatrix = " + builder);
|
|
firstFrame = false;
|
|
}
|
|
|
|
if (blendEnabled) {
|
|
GLES20.glDisable(GLES20.GL_BLEND);
|
|
blendEnabled = false;
|
|
}
|
|
|
|
int texture;
|
|
int target;
|
|
int index;
|
|
float[] stMatrix;
|
|
if (filterShaders != null) {
|
|
filterShaders.onVideoFrameUpdate(mSTMatrix);
|
|
|
|
GLES20.glViewport(0, 0, originalWidth, originalHeight);
|
|
filterShaders.drawSkinSmoothPass();
|
|
filterShaders.drawEnhancePass();
|
|
filterShaders.drawSharpenPass();
|
|
filterShaders.drawCustomParamsPass();
|
|
boolean blurred = filterShaders.drawBlurPass();
|
|
|
|
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
|
|
if (transformedWidth != originalWidth || transformedHeight != originalHeight) {
|
|
GLES20.glViewport(0, 0, transformedWidth, transformedHeight);
|
|
}
|
|
|
|
texture = filterShaders.getRenderTexture(blurred ? 0 : 1);
|
|
index = 1;
|
|
target = GLES20.GL_TEXTURE_2D;
|
|
stMatrix = mSTMatrixIdentity;
|
|
} else {
|
|
texture = mTextureID;
|
|
index = 0;
|
|
target = GLES11Ext.GL_TEXTURE_EXTERNAL_OES;
|
|
stMatrix = mSTMatrix;
|
|
}
|
|
|
|
GLES20.glUseProgram(mProgram[index]);
|
|
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
|
GLES20.glBindTexture(target, texture);
|
|
|
|
GLES20.glVertexAttribPointer(maPositionHandle[index], 2, GLES20.GL_FLOAT, false, 8, verticesBuffer);
|
|
GLES20.glEnableVertexAttribArray(maPositionHandle[index]);
|
|
GLES20.glVertexAttribPointer(maTextureHandle[index], 2, GLES20.GL_FLOAT, false, 8, renderTextureBuffer);
|
|
GLES20.glEnableVertexAttribArray(maTextureHandle[index]);
|
|
|
|
GLES20.glUniformMatrix4fv(muSTMatrixHandle[index], 1, false, stMatrix, 0);
|
|
GLES20.glUniformMatrix4fv(muMVPMatrixHandle[index], 1, false, mMVPMatrix, 0);
|
|
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
|
}
|
|
if (paintTexture != null || stickerTexture != null) {
|
|
GLES20.glUseProgram(simpleShaderProgram);
|
|
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
|
|
|
GLES20.glUniform1i(simpleSourceImageHandle, 0);
|
|
GLES20.glEnableVertexAttribArray(simpleInputTexCoordHandle);
|
|
GLES20.glVertexAttribPointer(simpleInputTexCoordHandle, 2, GLES20.GL_FLOAT, false, 8, textureBuffer);
|
|
GLES20.glEnableVertexAttribArray(simplePositionHandle);
|
|
}
|
|
if (paintTexture != null) {
|
|
for (int a = 0; a < paintTexture.length; a++) {
|
|
drawTexture(true, paintTexture[a]);
|
|
}
|
|
}
|
|
if (stickerTexture != null) {
|
|
for (int a = 0, N = mediaEntities.size(); a < N; a++) {
|
|
VideoEditedInfo.MediaEntity entity = mediaEntities.get(a);
|
|
if (entity.ptr != 0) {
|
|
RLottieDrawable.getFrame(entity.ptr, (int) entity.currentFrame, stickerBitmap, 512, 512, stickerBitmap.getRowBytes(), true);
|
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]);
|
|
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0);
|
|
entity.currentFrame += entity.framesPerDraw;
|
|
if (entity.currentFrame >= entity.metadata[0]) {
|
|
entity.currentFrame = 0;
|
|
}
|
|
drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0);
|
|
} else if (entity.bitmap != null) {
|
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]);
|
|
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, entity.bitmap, 0);
|
|
drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0);
|
|
}
|
|
}
|
|
}
|
|
GLES20.glFinish();
|
|
}
|
|
|
|
private void drawTexture(boolean bind, int texture) {
|
|
drawTexture(bind, texture, -10000, -10000, -10000, -10000, 0, false);
|
|
}
|
|
|
|
private void drawTexture(boolean bind, int texture, float x, float y, float w, float h, float rotation, boolean mirror) {
|
|
if (!blendEnabled) {
|
|
GLES20.glEnable(GLES20.GL_BLEND);
|
|
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
|
|
blendEnabled = true;
|
|
}
|
|
if (x <= -10000) {
|
|
bitmapData[0] = -1.0f;
|
|
bitmapData[1] = 1.0f;
|
|
|
|
bitmapData[2] = 1.0f;
|
|
bitmapData[3] = 1.0f;
|
|
|
|
bitmapData[4] = -1.0f;
|
|
bitmapData[5] = -1.0f;
|
|
|
|
bitmapData[6] = 1.0f;
|
|
bitmapData[7] = -1.0f;
|
|
} else {
|
|
x = x * 2 - 1.0f;
|
|
y = (1.0f - y) * 2 - 1.0f;
|
|
w = w * 2;
|
|
h = h * 2;
|
|
|
|
bitmapData[0] = x;
|
|
bitmapData[1] = y;
|
|
|
|
bitmapData[2] = x + w;
|
|
bitmapData[3] = y;
|
|
|
|
bitmapData[4] = x;
|
|
bitmapData[5] = y - h;
|
|
|
|
bitmapData[6] = x + w;
|
|
bitmapData[7] = y - h;
|
|
}
|
|
float mx = (bitmapData[0] + bitmapData[2]) / 2;
|
|
if (mirror) {
|
|
float temp = bitmapData[2];
|
|
bitmapData[2] = bitmapData[0];
|
|
bitmapData[0] = temp;
|
|
|
|
temp = bitmapData[6];
|
|
bitmapData[6] = bitmapData[4];
|
|
bitmapData[4] = temp;
|
|
}
|
|
if (rotation != 0) {
|
|
float ratio = transformedWidth / (float) transformedHeight;
|
|
float my = (bitmapData[5] + bitmapData[1]) / 2;
|
|
for (int a = 0; a < 4; a++) {
|
|
float x1 = bitmapData[a * 2 ] - mx;
|
|
float y1 = (bitmapData[a * 2 + 1] - my) / ratio;
|
|
bitmapData[a * 2 ] = (float) (x1 * Math.cos(rotation) - y1 * Math.sin(rotation)) + mx;
|
|
bitmapData[a * 2 + 1] = (float) (x1 * Math.sin(rotation) + y1 * Math.cos(rotation)) * ratio + my;
|
|
}
|
|
}
|
|
bitmapVerticesBuffer.put(bitmapData).position(0);
|
|
GLES20.glVertexAttribPointer(simplePositionHandle, 2, GLES20.GL_FLOAT, false, 8, bitmapVerticesBuffer);
|
|
|
|
if (bind) {
|
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
|
|
}
|
|
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
|
}
|
|
|
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
|
public void setBreakStrategy(EditTextOutline editText) {
|
|
editText.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
|
|
}
|
|
|
|
@SuppressLint("WrongConstant")
|
|
public void surfaceCreated() {
|
|
for (int a = 0; a < mProgram.length; a++) {
|
|
mProgram[a] = createProgram(VERTEX_SHADER, a == 0 ? FRAGMENT_EXTERNAL_SHADER : FRAGMENT_SHADER);
|
|
maPositionHandle[a] = GLES20.glGetAttribLocation(mProgram[a], "aPosition");
|
|
maTextureHandle[a] = GLES20.glGetAttribLocation(mProgram[a], "aTextureCoord");
|
|
muMVPMatrixHandle[a] = GLES20.glGetUniformLocation(mProgram[a], "uMVPMatrix");
|
|
muSTMatrixHandle[a] = GLES20.glGetUniformLocation(mProgram[a], "uSTMatrix");
|
|
}
|
|
int[] textures = new int[1];
|
|
GLES20.glGenTextures(1, textures, 0);
|
|
mTextureID = textures[0];
|
|
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
|
|
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
|
|
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
|
|
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
|
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
|
|
|
if (filterShaders != null || imagePath != null || paintPath != null || mediaEntities != null) {
|
|
int vertexShader = FilterShaders.loadShader(GLES20.GL_VERTEX_SHADER, FilterShaders.simpleVertexShaderCode);
|
|
int fragmentShader = FilterShaders.loadShader(GLES20.GL_FRAGMENT_SHADER, FilterShaders.simpleFragmentShaderCode);
|
|
if (vertexShader != 0 && fragmentShader != 0) {
|
|
simpleShaderProgram = GLES20.glCreateProgram();
|
|
GLES20.glAttachShader(simpleShaderProgram, vertexShader);
|
|
GLES20.glAttachShader(simpleShaderProgram, fragmentShader);
|
|
GLES20.glBindAttribLocation(simpleShaderProgram, 0, "position");
|
|
GLES20.glBindAttribLocation(simpleShaderProgram, 1, "inputTexCoord");
|
|
|
|
GLES20.glLinkProgram(simpleShaderProgram);
|
|
int[] linkStatus = new int[1];
|
|
GLES20.glGetProgramiv(simpleShaderProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
|
|
if (linkStatus[0] == 0) {
|
|
GLES20.glDeleteProgram(simpleShaderProgram);
|
|
simpleShaderProgram = 0;
|
|
} else {
|
|
simplePositionHandle = GLES20.glGetAttribLocation(simpleShaderProgram, "position");
|
|
simpleInputTexCoordHandle = GLES20.glGetAttribLocation(simpleShaderProgram, "inputTexCoord");
|
|
simpleSourceImageHandle = GLES20.glGetUniformLocation(simpleShaderProgram, "sourceImage");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (filterShaders != null) {
|
|
filterShaders.create();
|
|
filterShaders.setRenderData(null, 0, mTextureID, originalWidth, originalHeight);
|
|
}
|
|
if (imagePath != null || paintPath != null) {
|
|
paintTexture = new int[(imagePath != null ? 1 : 0) + (paintPath != null ? 1 : 0)];
|
|
GLES20.glGenTextures(paintTexture.length, paintTexture, 0);
|
|
try {
|
|
for (int a = 0; a < paintTexture.length; a++) {
|
|
String path;
|
|
int angle = 0;
|
|
if (a == 0 && imagePath != null) {
|
|
path = imagePath;
|
|
try {
|
|
ExifInterface exif = new ExifInterface(path);
|
|
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
|
|
switch (orientation) {
|
|
case ExifInterface.ORIENTATION_ROTATE_90:
|
|
angle = 90;
|
|
break;
|
|
case ExifInterface.ORIENTATION_ROTATE_180:
|
|
angle = 180;
|
|
break;
|
|
case ExifInterface.ORIENTATION_ROTATE_270:
|
|
angle = 270;
|
|
break;
|
|
}
|
|
} catch (Throwable ignore) {
|
|
|
|
}
|
|
} else {
|
|
path = paintPath;
|
|
}
|
|
Bitmap bitmap = BitmapFactory.decodeFile(path);
|
|
if (bitmap != null) {
|
|
if (a == 0 && imagePath != null) {
|
|
Bitmap newBitmap = Bitmap.createBitmap(transformedWidth, transformedHeight, Bitmap.Config.ARGB_8888);
|
|
newBitmap.eraseColor(0xff000000);
|
|
Canvas canvas = new Canvas(newBitmap);
|
|
float scale;
|
|
if (angle == 90 || angle == 270) {
|
|
scale = Math.max(bitmap.getHeight() / (float) transformedWidth, bitmap.getWidth() / (float) transformedHeight);
|
|
} else {
|
|
scale = Math.max(bitmap.getWidth() / (float) transformedWidth, bitmap.getHeight() / (float) transformedHeight);
|
|
}
|
|
|
|
android.graphics.Matrix matrix = new android.graphics.Matrix();
|
|
matrix.postTranslate(-bitmap.getWidth() / 2, -bitmap.getHeight() / 2);
|
|
matrix.postScale(1.0f / scale, 1.0f / scale);
|
|
matrix.postRotate(angle);
|
|
matrix.postTranslate(newBitmap.getWidth() / 2, newBitmap.getHeight() / 2);
|
|
canvas.drawBitmap(bitmap, matrix, new Paint(Paint.FILTER_BITMAP_FLAG));
|
|
bitmap = newBitmap;
|
|
}
|
|
|
|
GLES20.glBindTexture(GL10.GL_TEXTURE_2D, paintTexture[a]);
|
|
GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
|
|
GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
|
|
GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
|
|
GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
|
|
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
|
|
}
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e(e);
|
|
}
|
|
}
|
|
if (mediaEntities != null) {
|
|
try {
|
|
stickerBitmap = Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888);
|
|
stickerTexture = new int[1];
|
|
GLES20.glGenTextures(1, stickerTexture, 0);
|
|
GLES20.glBindTexture(GL10.GL_TEXTURE_2D, stickerTexture[0]);
|
|
GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
|
|
GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
|
|
GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
|
|
GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
|
|
for (int a = 0, N = mediaEntities.size(); a < N; a++) {
|
|
VideoEditedInfo.MediaEntity entity = mediaEntities.get(a);
|
|
if (entity.type == 0) {
|
|
if ((entity.subType & 1) != 0) {
|
|
entity.metadata = new int[3];
|
|
entity.ptr = RLottieDrawable.create(entity.text, 512, 512, entity.metadata, false, null, false);
|
|
entity.framesPerDraw = entity.metadata[1] / videoFps;
|
|
} else {
|
|
if (Build.VERSION.SDK_INT >= 19) {
|
|
entity.bitmap = BitmapFactory.decodeFile(entity.text);
|
|
} else {
|
|
File path = new File(entity.text);
|
|
RandomAccessFile file = new RandomAccessFile(path, "r");
|
|
ByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, path.length());
|
|
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
|
bmOptions.inJustDecodeBounds = true;
|
|
Utilities.loadWebpImage(null, buffer, buffer.limit(), bmOptions, true);
|
|
entity.bitmap = Bitmaps.createBitmap(bmOptions.outWidth, bmOptions.outHeight, Bitmap.Config.ARGB_8888);
|
|
Utilities.loadWebpImage(entity.bitmap, buffer, buffer.limit(), null, true);
|
|
file.close();
|
|
}
|
|
if (entity.bitmap != null) {
|
|
float aspect = entity.bitmap.getWidth() / (float) entity.bitmap.getHeight();
|
|
if (aspect > 1) {
|
|
float h = entity.height / aspect;
|
|
entity.y += (entity.height - h) / 2;
|
|
entity.height = h;
|
|
} else if (aspect < 1) {
|
|
float w = entity.width * aspect;
|
|
entity.x += (entity.width - w) / 2;
|
|
entity.width = w;
|
|
}
|
|
}
|
|
}
|
|
} else if (entity.type == 1) {
|
|
EditTextOutline editText = new EditTextOutline(ApplicationLoader.applicationContext);
|
|
editText.setBackgroundColor(Color.TRANSPARENT);
|
|
editText.setPadding(AndroidUtilities.dp(7), AndroidUtilities.dp(7), AndroidUtilities.dp(7), AndroidUtilities.dp(7));
|
|
editText.setTextSize(TypedValue.COMPLEX_UNIT_PX, entity.fontSize);
|
|
editText.setText(entity.text);
|
|
editText.setTextColor(entity.color);
|
|
editText.setTypeface(null, Typeface.BOLD);
|
|
editText.setGravity(Gravity.CENTER);
|
|
editText.setHorizontallyScrolling(false);
|
|
editText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
|
editText.setFocusableInTouchMode(true);
|
|
editText.setInputType(editText.getInputType() | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES);
|
|
if (Build.VERSION.SDK_INT >= 23) {
|
|
setBreakStrategy(editText);
|
|
}
|
|
if ((entity.subType & 1) != 0) {
|
|
editText.setTextColor(0xffffffff);
|
|
editText.setStrokeColor(entity.color);
|
|
editText.setFrameColor(0);
|
|
editText.setShadowLayer(0, 0, 0, 0);
|
|
} else if ((entity.subType & 4) != 0) {
|
|
editText.setTextColor(0xff000000);
|
|
editText.setStrokeColor(0);
|
|
editText.setFrameColor(entity.color);
|
|
editText.setShadowLayer(0, 0, 0, 0);
|
|
} else {
|
|
editText.setTextColor(entity.color);
|
|
editText.setStrokeColor(0);
|
|
editText.setFrameColor(0);
|
|
editText.setShadowLayer(5, 0, 1, 0x66000000);
|
|
}
|
|
|
|
editText.measure(View.MeasureSpec.makeMeasureSpec(entity.viewWidth, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(entity.viewHeight, View.MeasureSpec.EXACTLY));
|
|
editText.layout(0, 0, entity.viewWidth, entity.viewHeight);
|
|
entity.bitmap = Bitmap.createBitmap(entity.viewWidth, entity.viewHeight, Bitmap.Config.ARGB_8888);
|
|
Canvas canvas = new Canvas(entity.bitmap);
|
|
editText.draw(canvas);
|
|
}
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
private int createProgram(String vertexSource, String fragmentSource) {
|
|
int vertexShader = FilterShaders.loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
|
|
if (vertexShader == 0) {
|
|
return 0;
|
|
}
|
|
int pixelShader = FilterShaders.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
|
|
if (pixelShader == 0) {
|
|
return 0;
|
|
}
|
|
int program = GLES20.glCreateProgram();
|
|
if (program == 0) {
|
|
return 0;
|
|
}
|
|
GLES20.glAttachShader(program, vertexShader);
|
|
GLES20.glAttachShader(program, pixelShader);
|
|
GLES20.glLinkProgram(program);
|
|
int[] linkStatus = new int[1];
|
|
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
|
|
if (linkStatus[0] != GLES20.GL_TRUE) {
|
|
GLES20.glDeleteProgram(program);
|
|
program = 0;
|
|
}
|
|
return program;
|
|
}
|
|
|
|
public void release() {
|
|
if (mediaEntities != null) {
|
|
for (int a = 0, N = mediaEntities.size(); a < N; a++) {
|
|
VideoEditedInfo.MediaEntity entity = mediaEntities.get(a);
|
|
if (entity.ptr != 0) {
|
|
RLottieDrawable.destroy(entity.ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|