把Android原生的View渲染到OpenGL Texture
http://blog.csdn.net/u010949962/article/details/41865777
最近要把Android 原生的View渲染到OpenGL GLSurfaceView中,起初想到的是截图的方法,也就是把View截取成bitmap后,再把Bitmap渲染到OpenGL中;但是明显这种方法是不可行的,面对一些高速动态更新的View,只有不停的对view 进行截图才能渲染出原生View的效果。
通过大量的Google终于在国外的网站找到了一个做过类似的先例(链接:http://www.felixjones.co.uk/neo%20website/Android_View/)。不过经过测试该方法只能渲染直接父类为View的view,也就是只能渲染一层View(如progressbar,没不能添加child的view),当该原生Android View包含很多子view时(也就是根View为FramLayout、或者linearLayout之类),无法实时的监听到View动态改变,OpenGL中只能不停的渲染该view,才能渲染出原生View的效果。但是这样一来不同的渲染会耗费大量的资源,降低应用程序的效率。理想中的话,是监听到了该View的内容或者其子view 的内容发生了变化(如:View中的字幕发生滚动)才进行渲染。
经过接近两周的努力我终于完美地实现了该效果,既然是站在别人的基础上得来的成果,那么该方法就应当被共享,所以产生了此文,不过只支持api 15以上的
步骤一:重写根View
1.设置该View 绘制自己:
- setWillNotDraw(false);
2.监听View的变化,重写View,用ViewTreeObServer来监听,方法如下:
- private void addOnPreDrawListener() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- final ViewTreeObserver mObserver = getViewTreeObserver();
- if (mObserver != null) {
- mObserver.addOnPreDrawListener(new OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (isDirty()) {//View或者子view发生变化
- invalidate();
- }
- return true;
- }
- });
- }
- }
- }
3.重写该View的onDraw方法:
- @Override
- protected void onDraw(Canvas canvas) {
- try {
- if (mSurface != null) {
- Canvas surfaceCanvas = mSurface.lockCanvas(null);
- super.dispatchDraw(surfaceCanvas);
- mSurface.unlockCanvasAndPost(surfaceCanvas);
- mSurface.release();
- mSurface = null;
- mSurface = new Surface(mSurfaceTexture);
- }
- } catch (OutOfResourcesException e) {
- e.printStackTrace();
- }
- }
步骤二:GLSurfaceView.Renderer
- class CustomRenderer implements GLSurfaceView.Renderer {
- int glSurfaceTex;
- private final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
- long currentTime;
- long previousTime;
- boolean b = false;
- int frameCount = 0;
- DirectDrawer mDirectDrawer;
- ActivityManager activityManager;
- MemoryInfo _memoryInfo;
- // Fixed values
- private int TEXTURE_WIDTH = 360;
- private int TEXTURE_HEIGHT = 360;
- Context context;
- private LauncherAppWidgetHostView addedWidgetView;
- private SurfaceTexture surfaceTexture = null;
- private Surface surface;
- float fps;
- public CustomRenderer(Context context, LauncherAppWidgetHostView addedWidgetView, Display mDisplay){
- this.context = context;
- this.addedWidgetView = addedWidgetView;
- TEXTURE_WIDTH = mDisplay.getWidth();
- TEXTURE_HEIGHT = mDisplay.getHeight();
- _memoryInfo = new MemoryInfo();
- activityManager = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
- }
- @Override
- public void onDrawFrame(GL10 gl) {
- synchronized (this) {
- surfaceTexture.updateTexImage();
- }
- activityManager.getMemoryInfo(_memoryInfo);
- GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
- GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
- GLES20.glEnable(GLES20.GL_BLEND);
- GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
- float[] mtx = new float[16];
- surfaceTexture.getTransformMatrix(mtx);
- mDirectDrawer.draw(mtx);
- calculateFps();
- //getAppMemorySize();
- //getRunningAppProcessInfo();
- //Log.v("onDrawFrame", "FPS: " + Math.round(fps) + ", availMem: " + Math.round(_memoryInfo.availMem / 1048576) + "MB");
- }
- private void getAppMemorySize(){
- ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- android.os.Debug.MemoryInfo[] memoryInfos = mActivityManager.getProcessMemoryInfo(new int[]{android.os.Process.myPid()});
- int size = memoryInfos[0].dalvikPrivateDirty;
- Log.w("getAppMemorySize", size / 1024 + " MB");
- }
- private void getRunningAppProcessInfo() {
- ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- //获得系统里正在运行的所有进程
- List<RunningAppProcessInfo> runningAppProcessesList = mActivityManager.getRunningAppProcesses();
- for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcessesList) {
- // 进程ID号
- int pid = runningAppProcessInfo.pid;
- // 用户ID
- int uid = runningAppProcessInfo.uid;
- // 进程名
- String processName = runningAppProcessInfo.processName;
- // 占用的内存
- int[] pids = new int[] {pid};
- Debug.MemoryInfo[] memoryInfo = mActivityManager.getProcessMemoryInfo(pids);
- int memorySize = memoryInfo[0].dalvikPrivateDirty;
- System.out.println("processName="+processName+",currentPid: "+ "pid= " +android.os.Process.myPid()+"----------->"+pid+",uid="+uid+",memorySize="+memorySize+"kb");
- }
- }
- @Override
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- surface = null;
- surfaceTexture = null;
- glSurfaceTex = Engine_CreateSurfaceTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT);
- Log.d("GLES20Ext", "glSurfaceTex" + glSurfaceTex);
- if (glSurfaceTex > 0) {
- surfaceTexture = new SurfaceTexture(glSurfaceTex);
- surfaceTexture.setDefaultBufferSize(TEXTURE_WIDTH, TEXTURE_HEIGHT);
- surface = new Surface(surfaceTexture);
- addedWidgetView.setSurface(surface);
- addedWidgetView.setSurfaceTexture(surfaceTexture);
- //addedWidgetView.setSurfaceTexture(surfaceTexture);
- mDirectDrawer = new DirectDrawer(glSurfaceTex);
- }
- }
- float calculateFps() {
- frameCount++;
- if (!b) {
- b = true;
- previousTime = System.currentTimeMillis();
- }
- long intervalTime = System.currentTimeMillis() - previousTime;
- if (intervalTime >= 1000) {
- b = false;
- fps = frameCount / (intervalTime / 1000f);
- frameCount = 0;
- Log.w("calculateFps", "FPS: " + fps);
- }
- return fps;
- }
- int Engine_CreateSurfaceTexture(int width, int height) {
- /*
- * Create our texture. This has to be done each time the surface is
- * created.
- */
- int[] textures = new int[1];
- GLES20.glGenTextures(1, textures, 0);
- glSurfaceTex = textures[0];
- if (glSurfaceTex > 0) {
- GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, glSurfaceTex);
- // Notice the use of GL_TEXTURE_2D for texture creation
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, width, height, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, null);
- GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
- GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
- GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- }
- return glSurfaceTex;
- }
- @Override
- public void onSurfaceChanged(GL10 gl, int width, int height) {
- }
- }
- public class DirectDrawer {
- private final String vertexShaderCode =
- "attribute vec4 vPosition;" +
- "attribute vec2 inputTextureCoordinate;" +
- "varying vec2 textureCoordinate;" +
- "void main()" +
- "{"+
- "gl_Position = vPosition;"+
- "textureCoordinate = inputTextureCoordinate;" +
- "}";
- private final String fragmentShaderCode =
- "#extension GL_OES_EGL_image_external : require\n"+
- "precision mediump float;" +
- "varying vec2 textureCoordinate;\n" +
- "uniform samplerExternalOES s_texture;\n" +
- "void main() {" +
- " gl_FragColor = texture2D( s_texture, textureCoordinate );\n" +
- "}";
- private FloatBuffer vertexBuffer, textureVerticesBuffer;
- private ShortBuffer drawListBuffer;
- private final int mProgram;
- private int mPositionHandle;
- private int mTextureCoordHandle;
- private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
- // number of coordinates per vertex in this array
- private static final int COORDS_PER_VERTEX = 2;
- private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
- static float squareCoords[] = {
- -1.0f, 0.0f,
- -1.0f, -2.2f,
- 1.0f, -2.2f,
- 1.0f, 0.0f,
- };
- static float textureVertices[] = {
- 0f, 0f,
- 0f, 1f,
- 1f, 1f,
- 1f, 0f,
- };
- private int texture;
- public DirectDrawer(int texture)
- {
- this.texture = texture;
- // initialize vertex byte buffer for shape coordinates
- ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
- bb.order(ByteOrder.nativeOrder());
- vertexBuffer = bb.asFloatBuffer();
- vertexBuffer.put(squareCoords);
- vertexBuffer.position(0);
- // initialize byte buffer for the draw list
- ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
- dlb.order(ByteOrder.nativeOrder());
- drawListBuffer = dlb.asShortBuffer();
- drawListBuffer.put(drawOrder);
- drawListBuffer.position(0);
- ByteBuffer bb2 = ByteBuffer.allocateDirect(textureVertices.length * 4);
- bb2.order(ByteOrder.nativeOrder());
- textureVerticesBuffer = bb2.asFloatBuffer();
- textureVerticesBuffer.put(textureVertices);
- textureVerticesBuffer.position(0);
- int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
- int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
- mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
- GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
- GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
- GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables
- }
- public void draw(float[] mtx)
- {
- GLES20.glUseProgram(mProgram);
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture);
- // get handle to vertex shader's vPosition member
- mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
- // Enable a handle to the triangle vertices
- GLES20.glEnableVertexAttribArray(mPositionHandle);
- // Prepare the <insert shape here> coordinate data
- GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
- mTextureCoordHandle = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");
- GLES20.glEnableVertexAttribArray(mTextureCoordHandle);
- // textureVerticesBuffer.clear();
- // textureVerticesBuffer.put( transformTextureCoordinates(
- // textureVertices, mtx ));
- // textureVerticesBuffer.position(0);
- GLES20.glVertexAttribPointer(mTextureCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureVerticesBuffer);
- GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
- // Disable vertex array
- GLES20.glDisableVertexAttribArray(mPositionHandle);
- GLES20.glDisableVertexAttribArray(mTextureCoordHandle);
- }
- private int loadShader(int type, String shaderCode){
- // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
- // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
- int shader = GLES20.glCreateShader(type);
- // add the source code to the shader and compile it
- GLES20.glShaderSource(shader, shaderCode);
- GLES20.glCompileShader(shader);
- return shader;
- }
- private float[] transformTextureCoordinates( float[] coords, float[] matrix)
- {
- float[] result = new float[ coords.length ];
- float[] vt = new float[4];
- for ( int i = 0 ; i < coords.length ; i += 2 ) {
- float[] v = { coords[i], coords[i+1], 0 , 1 };
- Matrix.multiplyMV(vt, 0, matrix, 0, v, 0);
- result[i] = vt[0];
- result[i+1] = vt[1];
- }
- return result;
- }
- }
步骤三:配置GLSurfaceView:
- GLSurfaceView glSurfaceView = new GLSurfaceView(getApplicationContext());
- // Setup the surface view for drawing to
- glSurfaceView.setEGLContextClientVersion(2);
- glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
- glSurfaceView.setRenderer(renderer);
- //glSurfaceView.setZOrderOnTop(true);
- // Add our WebView to the Android View hierarchy
- glSurfaceView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
效果如图所示,上面是猎豹清理大师的widget,下面是GLSurfaceView的Texture,原生的Widget和OpenGL中渲染的一模一样。并且点击widget进行清理时也能达到实时渲染的Veiw动画清理效果,源码链接:https://github.com/MrHuangXin/RenderViewToOpenGL/tree/master
把Android原生的View渲染到OpenGL Texture的更多相关文章
- Android原生编解码接口 MediaCodec 之——踩坑
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/gb702250823/article/d ...
- 拓展 Android 原生 CountDownTimer 倒计时
拓展 Android 原生 CountDownTimer 倒计时 [TOC] CountDownTimer 在系统的CountDownTimer上进行的修改,主要是拓展了功能,当然也保留了系统默认的模 ...
- android原生ExpandableListView
android原生可扩展ExpandableListView就是可以伸缩的listView,一条标题下面有多条内容. 这个list的adapter对的数据要求与普通ListView的数据要求也有一些差 ...
- Android 原生listview item伸展收缩效果
Android原生listview做的一个item的伸缩效果.*永远不要让你老大有机会改需求 package com.example.yunkanglast; import java.io.Seria ...
- Android原生跳转React不同页面(undefined is not an object)
继续上篇文章的demo,由于现在的项目是原生的,打算用部分页面试下react native,那么问题来了:react貌似只有一个入口 index.android.js,那么在不同的原生页面需要跳转到不 ...
- android 原生camera——设置模块修改
, 此篇博客是记一次客户需求修改,从上周五到现在正好一周时间,期间的各种酸爽,就不说了,还是来看大家关注的技术问题吧. 首先看下以前效果和修改后的效果: 修改前:修改后: 不知道有没有看明白,我在简单 ...
- Android进阶(二十七)Android原生扰人烦的布局
Android原生扰人烦的布局 在开发Android应用时,UI布局是一件令人烦恼的事情.下面主要讲解一下Android中的界面布局. 一.线性布局(LinearLayout) 线性布局分为: (1) ...
- Android原生嵌入React Native
1.首先集成的项目目录 我使用的是直接按照react-native init Project 的格式来导入的,也就是说,我的Android项目目录是跟node_modules是在一个目录下的. 我们i ...
- uni-app&H5&Android混合开发三 || uni-app调用Android原生方法的三种方式
前言: 关于H5的调用Android原生方法的方式有很多,在该片文章中我主要简单介绍三种与Android原生方法交互的方式. 一.H5+方法调用android原生方法 H5+ Android开发规范官 ...
随机推荐
- 个人博客开发之 xadmin 安装
项目源码下载:http://download.vhosts.cn xadmin 下载地址:https://github.com/sshwsfc/xadmin或 https://github.com/s ...
- Hibernate每个具体类一张表映射(使用注释)
在每个类创建一张表的情况下, 表中不使用Null值的列. 这种方法的缺点是在子类表中创建了重复的列. 在这里,我们需要在父类中使用@Inheritance(strategy = Inheritance ...
- winform 的 checklistbox动态绑定并选中值
绑定的代码:这里绑定的是一个泛型 BLL.PowerBLL powerbll = new BLL.PowerBLL(); checkpower.DataSource = powerbll.GetAll ...
- Android 自定义权限 (<permission> <uses-permission>)
在android系统的安全模型中,应用程序在默认的情况下不可以执行任何对其他应用程序,系统或者用户带来负面影响的操作.如果应用需要执行某些操作,就需要声明使用这个操作对应的权限. (在manifest ...
- TP系统常量信息
[系统常量信息] 获取系统常量信息: 如果加参数true,会分组显示: 显示如下: [跨控制器调用] 一个控制器在执行的时候,可以实例化另外一个控制,并通过对象访问其指定方法. 跨控制器调用可以节省我 ...
- 双基准快速排序(Dual-Pivot Quicksort)(转)
课本上常见的快速排序都是选择一个枢纽元(Pivot),基于这个枢纽元从前后双向扫描分成大于枢纽元和小于枢纽元的.而从JDK 7开始,java.util.Arrays.sort()使用双基准快速排序(D ...
- sql server 2008获取表的字段注释
SELECT 表名 then d.name else '' end, 表说明 then isnull(f.value,'') else '' end, 字段序号=a.colorder, 字段名=a.n ...
- 关于vue,angularjs1,react之间的对比
1.时间投入的问题:相对于react和angularjs,学习vue的时间成本低,而且容易上手. 2.JSX的可读性比较一般.代码的可读性不如vue,当然,vue也支持jsx,但是vue更提倡temp ...
- ehcache 配置持久化到硬盘(四)
Ehcache默认配置的话 为了提高效率,所以有一部分缓存是在内存中,然后达到配置的内存对象总量,则才根据策略持久化到硬盘中,这里是有一个问题的,假如系统突然中断运行 那内存中的那些缓存,直接被释放掉 ...
- 使用远程管理工具Xshell
介绍 目前常用的远程管理工具 Xshell -- 免费版/收费版 SecureCRT Putty 安装Xshell 选择免费版即可 连接服务器 连接成功 Xshell连接不上排查流程 还有可能是Lin ...