个性装扮展示完成
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package com.qxcm.moduleutil.bean;
|
||||
|
||||
import lombok.Data;
|
||||
/**
|
||||
*@author qx
|
||||
*@data 2025/6/7
|
||||
*@description: 装扮类型表
|
||||
*/
|
||||
@Data
|
||||
public class PersonaltyBean {
|
||||
private String id;
|
||||
private String name;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.qxcm.moduleutil.bean;
|
||||
|
||||
/**
|
||||
*@author qx
|
||||
*@data 2025/6/7
|
||||
*@description:
|
||||
*/
|
||||
public class SvgaModel {
|
||||
public static final int TYPE_GIFT = 0;
|
||||
public static final int TYPE_JUE = 1;
|
||||
public static final int TYPE_JUE_AND_APPROACH = 2;
|
||||
public static final int TYPE_APPROACH = 3;
|
||||
public String url;
|
||||
public int type;
|
||||
public String approachUrl;
|
||||
public String userName;
|
||||
public String nobilityName;
|
||||
|
||||
public SvgaModel() {
|
||||
}
|
||||
|
||||
public SvgaModel(String url) {
|
||||
this.type=TYPE_GIFT;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public SvgaModel(String url, int type) {
|
||||
this.url = url;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public SvgaModel(String url, int type, String approachUrl, String userName, String nobilityName) {
|
||||
this.url = url;
|
||||
this.type = type;
|
||||
this.approachUrl = approachUrl;
|
||||
this.userName = userName;
|
||||
this.nobilityName=nobilityName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
package com.qxcm.moduleutil.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.net.Uri;
|
||||
import android.opengl.GLES11Ext;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import com.blankj.utilcode.util.PathUtils;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.liulishuo.okdownload.DownloadTask;
|
||||
import com.liulishuo.okdownload.StatusUtil;
|
||||
import com.liulishuo.okdownload.core.cause.EndCause;
|
||||
import com.liulishuo.okdownload.core.cause.ResumeFailedCause;
|
||||
import com.liulishuo.okdownload.core.listener.DownloadListener1;
|
||||
import com.liulishuo.okdownload.core.listener.assist.Listener1Assist;
|
||||
import com.opensource.svgaplayer.SVGADrawable;
|
||||
import com.opensource.svgaplayer.SVGADynamicEntity;
|
||||
import com.opensource.svgaplayer.SVGAImageView;
|
||||
import com.opensource.svgaplayer.SVGAParser;
|
||||
import com.opensource.svgaplayer.SVGAVideoEntity;
|
||||
import com.qxcm.moduleutil.R;
|
||||
import com.qxcm.moduleutil.databinding.RoomViewSvgaAnimBinding;
|
||||
import com.qxcm.moduleutil.utils.Md5Utils;
|
||||
import com.qxcm.moduleutil.utils.logger.Logger;
|
||||
import com.tencent.bugly.idasc.crashreport.CrashReport;
|
||||
import com.tencent.qgame.animplayer.AnimConfig;
|
||||
import com.tencent.qgame.animplayer.inter.IAnimListener;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
|
||||
|
||||
public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
|
||||
@Override
|
||||
public void onFailed(int i, @Nullable String s) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoStart() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoRender(int i, @Nullable AnimConfig animConfig) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoComplete() {
|
||||
if (mType == 1) {
|
||||
mBinding.playView.startPlay(mFile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoDestroy() {
|
||||
|
||||
}
|
||||
|
||||
public enum RenderType {SVGA, MP4}
|
||||
|
||||
private RenderType renderType;
|
||||
private ExoPlayer exoPlayer;
|
||||
private PlayerView playerView;
|
||||
private SVGAImageView svgaSurface;
|
||||
private GLSurfaceView glSurfaceView;
|
||||
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
private ChannelSplitRenderer1 renderer;
|
||||
private int mType;//1:循环播放 2:播放一次停止播放
|
||||
private File mFile;
|
||||
|
||||
private RoomViewSvgaAnimBinding mBinding;
|
||||
|
||||
public AvatarFrameView(@NonNull Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public AvatarFrameView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public AvatarFrameView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mBinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.room_view_svga_anim, this, true);
|
||||
initViews();
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
// 初始化 ExoPlayer View
|
||||
playerView = new PlayerView(getContext());
|
||||
playerView.setUseController(false);
|
||||
playerView.setVisibility(View.GONE);
|
||||
addView(playerView);
|
||||
|
||||
// 初始化 SVGA View
|
||||
svgaSurface = new SVGAImageView(getContext());
|
||||
svgaSurface.setVisibility(View.GONE);
|
||||
addView(svgaSurface);
|
||||
|
||||
// // 初始化 GLSurfaceView
|
||||
// glSurfaceView = new GLSurfaceView(getContext());
|
||||
// glSurfaceView.setEGLContextClientVersion(2);
|
||||
// renderer = new ChannelSplitRenderer1();
|
||||
// glSurfaceView.setRenderer(renderer);
|
||||
// glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
|
||||
// glSurfaceView.setVisibility(View.GONE); // 默认隐藏
|
||||
// addView(glSurfaceView);
|
||||
|
||||
// 初始化 ExoPlayer
|
||||
exoPlayer = new ExoPlayer.Builder(getContext()).build();
|
||||
playerView.setPlayer(exoPlayer);
|
||||
|
||||
mBinding.playView.setAnimListener(this);
|
||||
}
|
||||
|
||||
public void setSource(String url, RenderType type, int type2) {
|
||||
clearPrevious();
|
||||
renderType = type;
|
||||
mType = type2;
|
||||
switch (type) {
|
||||
case SVGA:
|
||||
mBinding.playView.stopPlay();
|
||||
mBinding.playView.setVisibility(View.GONE);
|
||||
loadSVGA(url);
|
||||
break;
|
||||
case MP4:
|
||||
// loadMP4(url);
|
||||
mBinding.playView.setVisibility(View.VISIBLE);
|
||||
downloadAndPlayMp4(url);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadAndPlayMp4(String url) {
|
||||
DownloadTask task = new DownloadTask.Builder(url, PathUtils.getInternalAppCachePath()
|
||||
, Md5Utils.getStringMD5(url) + ".mp4")
|
||||
// the minimal interval millisecond for callback progress
|
||||
.setMinIntervalMillisCallbackProcess(100)
|
||||
// do re-download even if the task has already been completed in the past.
|
||||
.setPassIfAlreadyCompleted(false)
|
||||
.setAutoCallbackToUIThread(true)
|
||||
.build();
|
||||
if (StatusUtil.isCompleted(task)) {
|
||||
playMp4(task.getFile());
|
||||
mFile = task.getFile();
|
||||
} else {
|
||||
task.enqueue(new DownloadListener1() {
|
||||
@Override
|
||||
public void taskStart(@NonNull DownloadTask task, @NonNull Listener1Assist.Listener1Model model) {
|
||||
Logger.e("taskStart", model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retry(@NonNull DownloadTask task, @NonNull ResumeFailedCause cause) {
|
||||
Logger.e("retry", cause);
|
||||
CrashReport.postCatchedException(new RuntimeException("下载文件重试:" + cause == null ? "" : cause.name()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connected(@NonNull DownloadTask task, int blockCount, long currentOffset, long totalLength) {
|
||||
Logger.e("connected", blockCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void progress(@NonNull DownloadTask task, long currentOffset, long totalLength) {
|
||||
Logger.e("progress", currentOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskEnd(@NonNull DownloadTask task, @NonNull EndCause cause, @Nullable Exception realCause, @NonNull Listener1Assist.Listener1Model model) {
|
||||
Logger.e("taskEnd", model);
|
||||
playMp4(task.getFile());
|
||||
mFile = task.getFile();
|
||||
if (cause != null && cause != EndCause.COMPLETED) {
|
||||
// CrashReport.postCatchedException(new RuntimeException("下载任务结束:" + cause == null ? "" : cause.name() + "_realCause:" + realCause == null ? "" : realCause.getMessage()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void playMp4(File file) {
|
||||
if (file != null) {
|
||||
mBinding.playView.startPlay(file);
|
||||
|
||||
} else {
|
||||
// showAnim();
|
||||
// playMp4(file);
|
||||
CrashReport.postCatchedException(new RuntimeException("播放MP4失败:File is null"));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSVGA(String url) {
|
||||
svgaSurface.setVisibility(View.VISIBLE);
|
||||
try {
|
||||
new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() {
|
||||
@Override
|
||||
public void onComplete(SVGAVideoEntity videoItem) {
|
||||
SVGADrawable drawable = new SVGADrawable(videoItem, new SVGADynamicEntity());
|
||||
svgaSurface.setImageDrawable(drawable);
|
||||
svgaSurface.startAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMP4(String url) {
|
||||
svgaSurface.setVisibility(View.GONE);
|
||||
playerView.setVisibility(View.GONE);
|
||||
|
||||
glSurfaceView.setVisibility(View.VISIBLE);
|
||||
glSurfaceView.onResume();
|
||||
glSurfaceView.requestRender();
|
||||
// 使用 post 确保 GLSurfaceView 已完成 layout
|
||||
glSurfaceView.post(() -> {
|
||||
Log.d("@@@", "GLSurfaceView size after layout: " + glSurfaceView.getWidth() + "x" + glSurfaceView.getHeight());
|
||||
|
||||
glSurfaceView.onResume();
|
||||
glSurfaceView.requestRender();
|
||||
|
||||
renderer.setOnSurfaceTextureReadyListener(surfaceTexture -> {
|
||||
mainHandler.post(() -> {
|
||||
Surface surface = new Surface(surfaceTexture);
|
||||
|
||||
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(url));
|
||||
exoPlayer.setMediaItem(mediaItem);
|
||||
exoPlayer.setVideoSurface(surface);
|
||||
exoPlayer.prepare();
|
||||
exoPlayer.play();
|
||||
Log.d("@@@", "ExoPlayer state after play: " + exoPlayer.getPlaybackState());
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void clearPrevious() {
|
||||
if (exoPlayer != null) {
|
||||
exoPlayer.stop();
|
||||
exoPlayer.clearVideoSurface();
|
||||
}
|
||||
|
||||
if (svgaSurface.getDrawable() instanceof SVGADrawable) {
|
||||
((SVGADrawable) svgaSurface.getDrawable()).stop();
|
||||
}
|
||||
|
||||
if (playerView != null) playerView.setVisibility(View.GONE);
|
||||
if (svgaSurface != null) svgaSurface.setVisibility(View.GONE);
|
||||
// if (glSurfaceView != null) glSurfaceView.setVisibility(View.GONE);
|
||||
mBinding.playView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
if (exoPlayer != null) {
|
||||
exoPlayer.release();
|
||||
}
|
||||
|
||||
if (svgaSurface.getDrawable() instanceof SVGADrawable) {
|
||||
((SVGADrawable) svgaSurface.getDrawable()).stop();
|
||||
}
|
||||
|
||||
if (glSurfaceView != null) {
|
||||
glSurfaceView.onPause(); // 必须调用生命周期方法
|
||||
// glSurfaceView.requestRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.qxcm.moduleutil.widget
|
||||
|
||||
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.opengl.GLES20
|
||||
import android.opengl.Matrix
|
||||
|
||||
class ChannelSplitRenderer {
|
||||
|
||||
private val vertexShaderCode = """
|
||||
attribute vec4 aPosition;
|
||||
attribute vec2 aTexCoord;
|
||||
varying vec2 vTexCoord;
|
||||
void main() {
|
||||
gl_Position = aPosition;
|
||||
vTexCoord = aTexCoord;
|
||||
}
|
||||
"""
|
||||
|
||||
private val fragmentShaderCode = """
|
||||
precision mediump float;
|
||||
uniform sampler2D uTexture;
|
||||
varying vec2 vTexCoord;
|
||||
void main() {
|
||||
// 只使用左半部分作为最终颜色
|
||||
vec2 leftCoord = vec2(vTexCoord.x * 0.5, vTexCoord.y);
|
||||
vec4 color = texture2D(uTexture, leftCoord);
|
||||
|
||||
// 设置 alpha 为 1.0 表示完全不透明,或根据需求设为 0.0 表示全透明
|
||||
gl_FragColor = vec4(color.rgb, 0.0); // 左通道颜色 + 不透明
|
||||
}"""
|
||||
|
||||
private var program = 0
|
||||
private var positionHandle = 0
|
||||
private var texCoordHandle = 0
|
||||
private var textureHandle = 0
|
||||
private val projectionMatrix = FloatArray(16)
|
||||
private val modelMatrix = FloatArray(16)
|
||||
|
||||
fun onSurfaceCreated(surface: SurfaceTexture, width: Int, height: Int) {
|
||||
// 初始化着色器
|
||||
val vertexShader = ShaderUtils.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
|
||||
val fragmentShader = ShaderUtils.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
|
||||
|
||||
program = GLES20.glCreateProgram().also {
|
||||
GLES20.glAttachShader(it, vertexShader)
|
||||
GLES20.glAttachShader(it, fragmentShader)
|
||||
GLES20.glLinkProgram(it)
|
||||
}
|
||||
|
||||
positionHandle = GLES20.glGetAttribLocation(program, "aPosition")
|
||||
texCoordHandle = GLES20.glGetAttribLocation(program, "aTexCoord")
|
||||
textureHandle = GLES20.glGetUniformLocation(program, "uTexture")
|
||||
|
||||
// 初始化矩阵
|
||||
Matrix.setIdentityM(projectionMatrix, 0)
|
||||
Matrix.setIdentityM(modelMatrix, 0)
|
||||
|
||||
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
GLES20.glEnable(GLES20.GL_BLEND)
|
||||
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)
|
||||
}
|
||||
|
||||
fun onSurfaceChanged(width: Int, height: Int) {
|
||||
GLES20.glViewport(0, 0, width, height)
|
||||
}
|
||||
|
||||
fun onDrawFrame(textureId: Int) {
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
|
||||
GLES20.glUseProgram(program)
|
||||
|
||||
// 定义顶点坐标(全屏)
|
||||
val vertices = floatArrayOf(
|
||||
-1.0f, -1.0f, 0.0f,
|
||||
1.0f, -1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f
|
||||
)
|
||||
|
||||
// 修改纹理坐标,只映射左半部分视频内容到左侧屏幕
|
||||
val texCoords = floatArrayOf(
|
||||
0.0f, 1.0f, // 左下角
|
||||
0.5f, 1.0f, // 右下角(对应视频中间)
|
||||
0.0f, 0.0f, // 左上角
|
||||
0.5f, 0.0f // 右上角
|
||||
)
|
||||
|
||||
val vertexBuffer = ShaderUtils.createFloatBuffer(vertices)
|
||||
val texBuffer = ShaderUtils.createFloatBuffer(texCoords)
|
||||
|
||||
GLES20.glEnableVertexAttribArray(positionHandle)
|
||||
GLES20.glVertexAttribPointer(
|
||||
positionHandle, 3,
|
||||
GLES20.GL_FLOAT, false,
|
||||
0, vertexBuffer
|
||||
)
|
||||
|
||||
GLES20.glEnableVertexAttribArray(texCoordHandle)
|
||||
GLES20.glVertexAttribPointer(
|
||||
texCoordHandle, 2,
|
||||
GLES20.GL_FLOAT, false,
|
||||
0, texBuffer
|
||||
)
|
||||
|
||||
// 绑定纹理
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
|
||||
GLES20.glUniform1i(textureHandle, 0)
|
||||
|
||||
// 绘制
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
|
||||
|
||||
// 清理
|
||||
GLES20.glDisableVertexAttribArray(positionHandle)
|
||||
GLES20.glDisableVertexAttribArray(texCoordHandle)
|
||||
}
|
||||
|
||||
|
||||
fun release() {
|
||||
GLES20.glDeleteProgram(program)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package com.qxcm.moduleutil.widget;
|
||||
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.opengl.EGL14;
|
||||
import android.opengl.EGLConfig;
|
||||
import android.opengl.EGLContext;
|
||||
import android.opengl.EGLDisplay;
|
||||
import android.opengl.EGLSurface;
|
||||
import android.opengl.GLES11Ext;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.opengl.Matrix;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
|
||||
public class ChannelSplitRenderer1 implements GLSurfaceView.Renderer {
|
||||
|
||||
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_SHADER =
|
||||
"#extension GL_OES_EGL_image_external : require\n" +
|
||||
"precision mediump float;\n" +
|
||||
"varying vec2 vTextureCoord;\n" +
|
||||
"uniform samplerExternalOES sTexture;\n" +
|
||||
"void main() {\n" +
|
||||
" vec2 uv = vTextureCoord;\n" +
|
||||
" // 左边部分的 UV 坐标范围 (0.0, 0.1) 到 (0.6, 0.9)\n" +
|
||||
" if (uv.x >= 0.0 && uv.x <= 0.6 && uv.y >= 0.1 && uv.y <= 0.9) {\n" +
|
||||
" // 居中显示\n" +
|
||||
" vec2 newUV = vec2(uv.x * (1.0 / 0.6), uv.y); // 水平方向拉伸\n" +
|
||||
" gl_FragColor = texture2D(sTexture, newUV);\n" +
|
||||
" } else {\n" +
|
||||
" gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); // 设置为完全透明\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
|
||||
|
||||
private int mProgram;
|
||||
private int maPositionHandle;
|
||||
private int maTextureHandle;
|
||||
private int muMVPMatrixHandle;
|
||||
private int muSTMatrixHandle;
|
||||
|
||||
private float[] mMVPMatrix = new float[16];
|
||||
private float[] mSTMatrix = new float[16];
|
||||
|
||||
private SurfaceTexture surfaceTexture;
|
||||
private int externalTextureId = -1;
|
||||
|
||||
private final float[] mTriangleVerticesData = {
|
||||
// X, Y, Z, U, V
|
||||
-1.0f, -1.0f, 0, 0.f, 0.f,
|
||||
1.0f, -1.0f, 0, 1.f, 0.f,
|
||||
-1.0f, 1.0f, 0, 0.f, 1.f,
|
||||
1.0f, 1.0f, 0, 1.f, 1.f,
|
||||
};
|
||||
|
||||
private FloatBuffer mTriangleVertices;
|
||||
|
||||
public ChannelSplitRenderer1() {
|
||||
mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4)
|
||||
.order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
mTriangleVertices.put(mTriangleVerticesData).position(0);
|
||||
Matrix.setIdentityM(mSTMatrix, 0);
|
||||
}
|
||||
|
||||
public interface OnSurfaceTextureReadyListener {
|
||||
void onSurfaceTextureReady(SurfaceTexture surfaceTexture);
|
||||
}
|
||||
private OnSurfaceTextureReadyListener surfaceTextureReadyListener;
|
||||
|
||||
public void setOnSurfaceTextureReadyListener(OnSurfaceTextureReadyListener listener) {
|
||||
this.surfaceTextureReadyListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated(GL10 gl, javax.microedition.khronos.egl.EGLConfig config) {
|
||||
Log.d("@@@@", "onDrawFrame called");
|
||||
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
|
||||
GLES20.glDisable(GLES20.GL_STENCIL_TEST);
|
||||
GLES20.glDisable(GLES20.GL_BLEND);
|
||||
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 设置透明背景
|
||||
|
||||
int[] textures = new int[1];
|
||||
GLES20.glGenTextures(1, textures, 0);
|
||||
externalTextureId = textures[0];
|
||||
|
||||
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, externalTextureId);
|
||||
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);
|
||||
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);
|
||||
|
||||
surfaceTexture = new SurfaceTexture(externalTextureId);
|
||||
|
||||
mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
|
||||
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
|
||||
maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
|
||||
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
|
||||
muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
|
||||
|
||||
if (surfaceTextureReadyListener != null) {
|
||||
surfaceTextureReadyListener.onSurfaceTextureReady(surfaceTexture);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
GLES20.glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
private long lastTimestamp = -1;
|
||||
@Override
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
if (surfaceTexture != null) {
|
||||
surfaceTexture.updateTexImage();
|
||||
long timestamp = surfaceTexture.getTimestamp();
|
||||
|
||||
if (timestamp != lastTimestamp) {
|
||||
Log.d("@@@", "New frame received, timestamp: " + timestamp);
|
||||
lastTimestamp = timestamp;
|
||||
}
|
||||
|
||||
surfaceTexture.getTransformMatrix(mSTMatrix);
|
||||
} else {
|
||||
Log.e("@@@", "SurfaceTexture is null in onDrawFrame");
|
||||
}
|
||||
|
||||
GLES20.glUseProgram(mProgram);
|
||||
|
||||
Matrix.setIdentityM(mMVPMatrix, 0);
|
||||
|
||||
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
|
||||
GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);
|
||||
|
||||
mTriangleVertices.position(0);
|
||||
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 20, mTriangleVertices);
|
||||
GLES20.glEnableVertexAttribArray(maPositionHandle);
|
||||
|
||||
mTriangleVertices.position(3);
|
||||
GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, 20, mTriangleVertices);
|
||||
GLES20.glEnableVertexAttribArray(maTextureHandle);
|
||||
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
||||
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, externalTextureId);
|
||||
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
public SurfaceTexture getSurfaceTexture() {
|
||||
return surfaceTexture;
|
||||
}
|
||||
|
||||
private int loadShader(int shaderType, String source) {
|
||||
int shader = GLES20.glCreateShader(shaderType);
|
||||
GLES20.glShaderSource(shader, source);
|
||||
GLES20.glCompileShader(shader);
|
||||
int[] compiled = new int[1];
|
||||
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == 0) {
|
||||
return 0;
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
private int createProgram(String vertexSource, String fragmentSource) {
|
||||
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
|
||||
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
|
||||
int program = GLES20.glCreateProgram();
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
return program;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.qxcm.moduleutil.widget;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
import android.util.Log;
|
||||
|
||||
public class ShaderUtils {
|
||||
|
||||
private static final String TAG = "ShaderUtils";
|
||||
|
||||
// 创建并编译着色器
|
||||
public static int loadShader(int type, String shaderCode) {
|
||||
int shader = GLES20.glCreateShader(type);
|
||||
GLES20.glShaderSource(shader, shaderCode);
|
||||
GLES20.glCompileShader(shader);
|
||||
|
||||
int[] compiled = new int[1];
|
||||
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == 0) {
|
||||
Log.e(TAG, "Could NOT compile shader: " + GLES20.glGetShaderInfoLog(shader));
|
||||
GLES20.glDeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
// 创建 FloatBuffer
|
||||
public static FloatBuffer createFloatBuffer(float[] array) {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(array.length * 4);
|
||||
bb.order(ByteOrder.nativeOrder());
|
||||
FloatBuffer buffer = bb.asFloatBuffer();
|
||||
buffer.put(array);
|
||||
buffer.position(0);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
34
moduleUtil/src/main/res/layout/room_view_svga_anim.xml
Normal file
34
moduleUtil/src/main/res/layout/room_view_svga_anim.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<data>
|
||||
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- <com.opensource.svgaplayer.SVGAImageView-->
|
||||
<!-- android:id="@+id/image"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="0dp"-->
|
||||
<!-- android:scaleType="fitCenter"-->
|
||||
<!-- app:autoPlay="true"-->
|
||||
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||
<!-- app:layout_constraintStart_toStartOf="parent"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent"-->
|
||||
<!-- app:loopCount="1" />-->
|
||||
|
||||
<com.tencent.qgame.animplayer.AnimView
|
||||
android:id="@+id/play_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
28
moduleUtil/src/main/res/layout/room_view_svga_animation.xml
Normal file
28
moduleUtil/src/main/res/layout/room_view_svga_animation.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.opensource.svgaplayer.SVGAImageView
|
||||
android:id="@+id/iv_approach"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:autoPlay="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="750:667"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:loopCount="1" />
|
||||
|
||||
<com.opensource.svgaplayer.SVGAImageView
|
||||
android:id="@+id/iv_ripple1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:autoPlay="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:loopCount="1" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.example.modulevocal.conacts;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.qxcm.moduleutil.activity.IPresenter;
|
||||
import com.qxcm.moduleutil.activity.IView;
|
||||
import com.qxcm.moduleutil.bean.PersonaltyBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PersonalityConacts {
|
||||
public interface View extends IView<Activity> {
|
||||
void getPersonaltyList(List<PersonaltyBean> personaltyBean);
|
||||
|
||||
}
|
||||
public interface IMePre extends IPresenter {
|
||||
void getPersonaltyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.example.modulevocal.presenter;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.example.modulevocal.conacts.PersonalityConacts;
|
||||
import com.qxcm.moduleutil.bean.PersonaltyBean;
|
||||
import com.qxcm.moduleutil.http.BaseObserver;
|
||||
import com.qxcm.moduleutil.presenter.BasePresenter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
public class PersonalityPresenter extends BasePresenter<PersonalityConacts.View> implements PersonalityConacts.IMePre{
|
||||
public PersonalityPresenter(PersonalityConacts.View view, Context context) {
|
||||
super(view, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPersonaltyList() {
|
||||
api.getPersonaltyList(new BaseObserver<List<PersonaltyBean>>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
addDisposable(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(List<PersonaltyBean> personaltyBeans) {
|
||||
MvpRef.get().getPersonaltyList(personaltyBeans);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user