diff --git a/moduleUtil/src/main/java/com/qxcm/moduleutil/bean/PersonaltyBean.java b/moduleUtil/src/main/java/com/qxcm/moduleutil/bean/PersonaltyBean.java
new file mode 100644
index 00000000..8cdc1528
--- /dev/null
+++ b/moduleUtil/src/main/java/com/qxcm/moduleutil/bean/PersonaltyBean.java
@@ -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;
+}
diff --git a/moduleUtil/src/main/java/com/qxcm/moduleutil/bean/SvgaModel.java b/moduleUtil/src/main/java/com/qxcm/moduleutil/bean/SvgaModel.java
new file mode 100644
index 00000000..68a84119
--- /dev/null
+++ b/moduleUtil/src/main/java/com/qxcm/moduleutil/bean/SvgaModel.java
@@ -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;
+ }
+}
diff --git a/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/AvatarFrameView.java b/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/AvatarFrameView.java
new file mode 100644
index 00000000..7728796c
--- /dev/null
+++ b/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/AvatarFrameView.java
@@ -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();
+ }
+ }
+}
diff --git a/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/ChannelSplitRenderer.kt b/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/ChannelSplitRenderer.kt
new file mode 100644
index 00000000..93596cc1
--- /dev/null
+++ b/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/ChannelSplitRenderer.kt
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/ChannelSplitRenderer1.java b/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/ChannelSplitRenderer1.java
new file mode 100644
index 00000000..8d8b3c0d
--- /dev/null
+++ b/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/ChannelSplitRenderer1.java
@@ -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;
+ }
+}
diff --git a/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/ShaderUtils.java b/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/ShaderUtils.java
new file mode 100644
index 00000000..3e457128
--- /dev/null
+++ b/moduleUtil/src/main/java/com/qxcm/moduleutil/widget/ShaderUtils.java
@@ -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;
+ }
+}
diff --git a/moduleUtil/src/main/res/layout/room_view_svga_anim.xml b/moduleUtil/src/main/res/layout/room_view_svga_anim.xml
new file mode 100644
index 00000000..d8366cd3
--- /dev/null
+++ b/moduleUtil/src/main/res/layout/room_view_svga_anim.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/moduleUtil/src/main/res/layout/room_view_svga_animation.xml b/moduleUtil/src/main/res/layout/room_view_svga_animation.xml
new file mode 100644
index 00000000..321a272b
--- /dev/null
+++ b/moduleUtil/src/main/res/layout/room_view_svga_animation.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modulevocal/src/main/java/com/example/modulevocal/conacts/PersonalityConacts.java b/modulevocal/src/main/java/com/example/modulevocal/conacts/PersonalityConacts.java
new file mode 100644
index 00000000..c8a23e9d
--- /dev/null
+++ b/modulevocal/src/main/java/com/example/modulevocal/conacts/PersonalityConacts.java
@@ -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 {
+ void getPersonaltyList(List personaltyBean);
+
+ }
+ public interface IMePre extends IPresenter {
+ void getPersonaltyList();
+ }
+}
diff --git a/modulevocal/src/main/java/com/example/modulevocal/presenter/PersonalityPresenter.java b/modulevocal/src/main/java/com/example/modulevocal/presenter/PersonalityPresenter.java
new file mode 100644
index 00000000..79a54ea2
--- /dev/null
+++ b/modulevocal/src/main/java/com/example/modulevocal/presenter/PersonalityPresenter.java
@@ -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 implements PersonalityConacts.IMePre{
+ public PersonalityPresenter(PersonalityConacts.View view, Context context) {
+ super(view, context);
+ }
+
+ @Override
+ public void getPersonaltyList() {
+ api.getPersonaltyList(new BaseObserver>() {
+ @Override
+ public void onSubscribe(Disposable d) {
+ addDisposable(d);
+ }
+
+ @Override
+ public void onNext(List personaltyBeans) {
+ MvpRef.get().getPersonaltyList(personaltyBeans);
+ }
+ });
+ }
+}