上图的实现,如果是用GLSurfaceView实现,那会相对比较简单,直接在设置的Renderer实现类中实现gl展示即可,但是使用TextureView就没那么方便了,一般TextureView与OpenGL和结合就是相机预览和视频播放了,那如果是一般的gles展示呢? 这就需要重新创建一个GL线程了(相比之下,这种方式是真真不好的,通过实践发现:这种实现方式CPU占用率比GLSurfaceView的CPU占用率还高。再者GLSurfaceView本就对渲染同步、状态控制等做了优化封装),但既然已经做了,就写下来mark一下!
那这个demo主要有3个类,主要看代码,代码中有注释。
1.GLESTextureView,这个类继承自TextureView,主要是添加了setRenderer和setRenderMode方法,使其用起来像GLSurfaceView一样。
2.GLESTVThread,这是一个线程类,在GLESTextureView的SurfaceTexture准备好之后开启该线程作为一个GL线程(GL的一些操作都要在该线程中去实现)。
3.IGLESRenderer,该类是GL线程流程的接口,该接口的实现可用于GLESTextureView的setRenderer,也可以用于GLSurfaceView中的renderer的方法体实现。
package com.dandy.helper.gles; /** * <pre> * GLES里用到的用于渲染的一个接口。 * 如果是GLSurfaceView要用到,则其对应的GLSurfaceView.Renderer可以来调用IGLESRenderer的实现类来实现逻辑 * 如果是TextureView要用到,则使用自定义的一个线程里调用IGLESRenderer的实现类来做一个类似于GLSurfaceView.Renderer的操作 * 所以IGLESRenderer中的方法都要在GL线程里运行(TextureView创建一个线程,把它当做一个GL线程) * </pre> * * @author flycatdeng * */ public interface IGLESRenderer { /** * <pre> * Surface创建好之后 * </pre> */ public void onSurfaceCreated(); /** * <pre> * 界面大小有更改 * </pre> * * @param width * @param height */ public void onSurfaceChanged(int width, int height); /** * <pre> * 绘制每一帧 * </pre> */ public void onDrawFrame(); /** * <pre> * Activity的onResume时的操作 * </pre> */ public void onResume(); /** * <pre> * Activity的onPause时的操作 * </pre> */ public void onPause(); /** * <pre> * Activity的onDestroy时的操作 * </pre> */ public void onDestroy(); }
package com.dandy.module.gles.textureview; import android.content.Context; import android.graphics.SurfaceTexture; import android.util.AttributeSet; import android.view.TextureView; import com.dandy.helper.gles.IGLESRenderer; /** * <pre> * 一个类似于GLSurfaceView的TextureView,用于显示opengl * {@link #setRenderer(IGLESRenderer)}类似于GLSurfaceView的setRenderer(Renderer) * {{@link #setRenderMode(int)}类似于GLSurfaceView的setRenderMode(int) * 详细调用可模仿com.dandy.gldemo.glestextureview.DemoGlesTextureView * 没事可看<a href='http://blog.csdn.net/fuyajun01/article/details/8931647#' >参照1</>或者<a href="http://www.jianshu.com/p/b2d949ab1a1a">参照2</a> * </pre> * * @author flycatdeng * */ public class GLESTextureView extends TextureView implements TextureView.SurfaceTextureListener { public final static int RENDERMODE_WHEN_DIRTY = 0; public final static int RENDERMODE_CONTINUOUSLY = 1; private GLESTVThread mGLThread; private IGLESRenderer mRenderer; private int mRendererMode = RENDERMODE_CONTINUOUSLY; public GLESTextureView(Context context) { super(context); init(context); } public GLESTextureView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } /** * <pre> * 类似于GLSurfaceView的setRenderer * </pre> */ public void setRenderer(IGLESRenderer renderer) { mRenderer = renderer; } /** * <pre> * 类似于GLSurfaceView的setRenderMode * 渲染模式,是循环刷新,还是请求的时候刷新 * </pre> */ public void setRenderMode(int mode) { mRendererMode = mode; } /** * Request that the renderer render a frame. This method is typically used when the render mode has been set to {@link #RENDERMODE_WHEN_DIRTY}, so * that frames are only rendered on demand. May be called from any thread. Must not be called before a renderer has been set. */ public void requestRender() { if (mRendererMode != RENDERMODE_WHEN_DIRTY) { return; } mGLThread.requestRender(); } private void init(Context context) { setSurfaceTextureListener(this); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { mGLThread = new GLESTVThread(surface, mRenderer);// 创建一个线程,作为GL线程 mGLThread.setRenderMode(mRendererMode); mGLThread.start(); mGLThread.onSurfaceChanged(width, height); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { mGLThread.onSurfaceChanged(width, height); } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } public void onResume() { if (mGLThread != null) { mGLThread.onResume(); } } public void onPause() { if (mGLThread != null) { mGLThread.onPause(); } } public void onDestroy() { if (mGLThread != null) { mGLThread.onDestroy(); } } }
package com.dandy.module.gles.textureview; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import android.graphics.SurfaceTexture; import android.opengl.GLUtils; import com.dandy.helper.android.LogHelper; import com.dandy.helper.gles.IGLESRenderer; import com.dandy.helper.java.PendingThreadAider; /** * <pre> * TextureView中要用的GLThread * <a href="http://www.cnblogs.com/kiffa/archive/2013/02/21/2921123.html">一个很好的EGL相关学习参考</a> * 一般在Android中使用OpenGL ES,总是会从GLSurfaceView和Renderer开始,只需要提供一个合适的SurfaceHolder,就可以完成整个环境初始化,并进行绘制。 * GLSurfaceView和Renderer事实上只是在本文描述的基础上封装了一些便利的功能,便于开发者开发,比如渲染同步、状态控制、主(渲染)循环等 * </pre> * * @author flycatdeng */ class GLESTVThread extends Thread { private static final String TAG = "GLESTVThread"; private SurfaceTexture mSurfaceTexture; private EGL10 mEgl; private EGLDisplay mEglDisplay = EGL10.EGL_NO_DISPLAY;// 显示设备 private EGLSurface mEglSurface = EGL10.EGL_NO_SURFACE; private EGLContext mEglContext = EGL10.EGL_NO_CONTEXT; // private GL mGL; private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; private static final int EGL_OPENGL_ES2_BIT = 4; private IGLESRenderer mRenderer; private PendingThreadAider mPendingThreadAider = new PendingThreadAider(); private boolean mNeedRenderring = true; private Object LOCK = new Object(); private boolean mIsPaused = false; public GLESTVThread(SurfaceTexture surface, IGLESRenderer renderer) { mSurfaceTexture = surface; mRenderer = renderer; } @Override public void run() { LogHelper.d(TAG, LogHelper.getThreadName()); initGLESContext(); mRenderer.onSurfaceCreated(); while (mNeedRenderring) { mPendingThreadAider.runPendings();// 执行未执行的,或要执行的事件。(后期可以开放以便模仿GLSurfaceView的queueEvent(Runnable r)) mRenderer.onDrawFrame();// 绘制 // 一帧完成之后,调用eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)来显示 mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);// 这一句不能少啊,少了就GG了,一片空白 // 1.凡是onPause都要停止,2.如果是onResume的状态,如果是循环刷新则会继续下一次循环,否则会暂停等待调用requestRender() if (mIsPaused) { pauseWhile(); } else if (mRendererMode == GLESTextureView.RENDERMODE_WHEN_DIRTY) { pauseWhile(); } } destoryGLESContext(); } private void initGLESContext() { LogHelper.d(TAG, LogHelper.getThreadName()); mEgl = (EGL10) EGLContext.getEGL(); mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);// 获取显示设备 if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { throw new RuntimeException("eglGetdisplay failed : " + GLUtils.getEGLErrorString(mEgl.eglGetError())); } int[] version = new int[2]; if (!mEgl.eglInitialize(mEglDisplay, version)) {// //version中存放EGL 版本号,int[0]为主版本号,int[1]为子版本号 throw new RuntimeException("eglInitialize failed : " + GLUtils.getEGLErrorString(mEgl.eglGetError())); } // 构造需要的特性列表 int[] configAttribs = { // EGL10.EGL_BUFFER_SIZE, 32,// EGL10.EGL_ALPHA_SIZE, 8, // 指定Alpha大小,以下四项实际上指定了像素格式 EGL10.EGL_BLUE_SIZE, 8, // 指定B大小 EGL10.EGL_GREEN_SIZE, 8,// 指定G大小 EGL10.EGL_RED_SIZE, 8,// 指定RGB中的R大小(bits) EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,// 指定渲染api类别,这里或者是硬编码的4,或者是EGL14.EGL_OPENGL_ES2_BIT EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT, EGL10.EGL_NONE// 总是以EGL10.EGL_NONE结尾 }; int[] numConfigs = new int[1]; EGLConfig[] configs = new EGLConfig[1]; // eglChooseConfig(display, attributes, configs, num, configNum); // 用于获取满足attributes的所有config,参数1、2其意明显,参数3用于存放输出的configs,参数4指定最多输出多少个config,参数5由EGL系统写入,表明满足attributes的config一共有多少个 if (!mEgl.eglChooseConfig(mEglDisplay, configAttribs, configs, 1, numConfigs)) {// 获取所有满足attributes的configs,并选择一个 throw new RuntimeException("eglChooseConfig failed : " + GLUtils.getEGLErrorString(mEgl.eglGetError())); } int[] contextAttribs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};// attrib_list,目前可用属性只有EGL_CONTEXT_CLIENT_VERSION, 1代表OpenGL ES 1.x, // 2代表2.0。同样在Android4.2之前,没有EGL_CONTEXT_CLIENT_VERSION这个属性,只能使用硬编码0x3098代替 mEglContext = mEgl.eglCreateContext(mEglDisplay, configs[0], EGL10.EGL_NO_CONTEXT, // share_context,是否有context共享,共享的contxt之间亦共享所有数据。EGL_NO_CONTEXT代表不共享 contextAttribs);// 创建context mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, configs[0], mSurfaceTexture,// 负责对Android Surface的管理 null// Surface属性 );// 获取显存,create a new EGL window surface if (mEglSurface == EGL10.EGL_NO_SURFACE || mEglContext == EGL10.EGL_NO_CONTEXT) { int error = mEgl.eglGetError(); if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { throw new RuntimeException("eglCreateWindowSurface returned EGL_BAD_NATIVE_WINDOW. "); } throw new RuntimeException("eglCreateWindowSurface failed : " + GLUtils.getEGLErrorString(mEgl.eglGetError())); } if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {// 设置为当前的渲染环境 throw new RuntimeException("eglMakeCurrent failed : " + GLUtils.getEGLErrorString(mEgl.eglGetError())); } // mGL = mEglContext.getGL(); } private void pauseWhile() { synchronized (LOCK) { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void destoryGLESContext() { LogHelper.d(TAG, LogHelper.getThreadName()); mEgl.eglDestroyContext(mEglDisplay, mEglContext); mEgl.eglDestroySurface(mEglDisplay, mEglSurface); mEglContext = EGL10.EGL_NO_CONTEXT; mEglSurface = EGL10.EGL_NO_SURFACE; } public void onPause() { mRenderer.onPause(); mIsPaused = true; } public void onResume() { mRenderer.onResume(); mIsPaused = false; requestRender(); } public void onSurfaceChanged(final int width, final int height) { mPendingThreadAider.addToPending(new Runnable() {// 在GL线程中执行 @Override public void run() { mRenderer.onSurfaceChanged(width, height); } }); } private int mRendererMode = GLESTextureView.RENDERMODE_CONTINUOUSLY; public void setRenderMode(int mode) { mRendererMode = mode; } public void requestRender() { synchronized (LOCK) { LOCK.notifyAll(); } } public void onDestroy() { mNeedRenderring = false; mRenderer.onDestroy(); destoryGLESContext(); } }
demo:https://github.com/flycatdeng/GLTextureViewDemo
一个Activity里两个GLSurfaceView无法同时渲染,所以如果要分多个区渲染的话,这个TextureView倒也可以去用用
相关推荐
Java-美妆神域_3rm1m18i_221-wx.zip
51单片机的温度监测与控制(温控风扇)
电赛案例,C++简单的智能家居系统,其中包含了温度监测、光照控制和报警系统。该系统可以: 监控室内温度:当温度超过设定阈值时,触发警报。 自动调节光照:根据光线传感器的值自动调节LED灯的亮度。 入侵检测:通过红外传感器检测入侵,并触发警报。
圣诞树 html版 可修改祝福语。 记事本或vscode编辑html文件:ctrl+F寻找”myLabels“关键词,定位到该处即可修改祝福语
【资源说明】 基于python编写的selenium自动化测试框架,采用PO模式,页面元素采用yaml进行管理资料齐全+详细文档+高分项目+源码.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
屏幕截图 2024-12-21 170434
基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理 请假信息管理 成绩信息管理 基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理 请假信息管理 成绩信息管理基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理 请假信息管理 成绩信息管理基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理 请假信息管理 成绩信息管理基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理
径向基函数内核 – 机器学习 内核在将数据转换为更高维空间方面发挥着重要作用,使算法能够学习复杂的模式和关系。在众多的内核函数中,径向基函数(RBF)内核作为一种多功能且强大的工具脱颖而出。在本文中,我们深入探讨了RBF内核的复杂性,探讨了它的数学公式、直观理解、实际应用及其在各种机器学习算法中的重要性。
详细介绍及样例数据:https://blog.csdn.net/samLi0620/article/details/144636765
51单片机控制的智能小车.7z
【资源说明】 基于卷积神经网络的数字手势识别安卓APP,识别数字手势0-10详细文档+全部资料+优秀项目+源码.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
python 使用sqlserver必须要这个问题,没办法,只能满世界的找地方下载,终于让我下载到了,现在分享给大家使用
四川采矿场生产安全事故管理制度
简约灰粉共存版_8.0.53.apk
ECharts散点图-全国主要城市空气质量(百度地图)
四川采矿场安全检查管理规定
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;
空中俯视物体检测9-YOLOv5数据集合集.rar使用YOLO算法从图像中检测对象-V2 2023-05-11 2:51 PM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括1015张图像。 以YOLO V5 PYTORCH格式注释检测对象 - 图像。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整大小为640x640(拉伸) 没有应用图像增强技术。
词云图
Python高分毕设——Python&Opencv手势识别系统(完整源码&自定义UI操作界面&视频教程) Python高分毕设——Python&Opencv手势识别系统(完整源码&自定义UI操作界面&视频教程) 使用了OpenCV的视频采集, 图像色域转换, 颜色通道分割, 高斯滤波, OSTU自动阈值, 凸点检测, 边缘检测, 余弦定理计算手势等功能. 准备工作 安装 Python-OpenCV 库 pip install opencv-python -i https://mirrors.ustc.edu.cn/pypi/web/simple 利用 -i 为pip指令镜像源, 这里使用电子科技大学的源, 速度比官方源更快. 安装 Numpy 科学计算库 pip install numpy -i https://mirrors.ustc.edu.cn/pypi/web/simple 安装 PyAutogui 库 pip install pyautogui -i https://mirrors.ustc.edu.cn/pypi/web/simple 代码实现 import nu