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 绘制自己:

  1. setWillNotDraw(false);

2.监听View的变化,重写View,用ViewTreeObServer来监听,方法如下:

  1. private void addOnPreDrawListener() {
  2. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
  3. final ViewTreeObserver mObserver = getViewTreeObserver();
  4. if (mObserver != null) {
  5. mObserver.addOnPreDrawListener(new OnPreDrawListener() {
  6. @Override
  7. public boolean onPreDraw() {
  8. if (isDirty()) {//View或者子view发生变化
  9. invalidate();
  10. }
  11. return true;
  12. }
  13. });
  14. }
  15. }
  16. }

3.重写该View的onDraw方法:

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. try {
  4. if (mSurface != null) {
  5. Canvas surfaceCanvas = mSurface.lockCanvas(null);
  6. super.dispatchDraw(surfaceCanvas);
  7. mSurface.unlockCanvasAndPost(surfaceCanvas);
  8. mSurface.release();
  9. mSurface = null;
  10. mSurface = new Surface(mSurfaceTexture);
  11. }
  12. } catch (OutOfResourcesException e) {
  13. e.printStackTrace();
  14. }
  15. }

步骤二:GLSurfaceView.Renderer

  1. class CustomRenderer implements GLSurfaceView.Renderer {
  2. int glSurfaceTex;
  3. private final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
  4. long currentTime;
  5. long previousTime;
  6. boolean b = false;
  7. int frameCount = 0;
  8. DirectDrawer mDirectDrawer;
  9. ActivityManager activityManager;
  10. MemoryInfo _memoryInfo;
  11. // Fixed values
  12. private int TEXTURE_WIDTH = 360;
  13. private int TEXTURE_HEIGHT = 360;
  14. Context context;
  15. private LauncherAppWidgetHostView addedWidgetView;
  16. private SurfaceTexture surfaceTexture = null;
  17. private Surface surface;
  18. float fps;
  19. public CustomRenderer(Context context, LauncherAppWidgetHostView addedWidgetView, Display mDisplay){
  20. this.context = context;
  21. this.addedWidgetView = addedWidgetView;
  22. TEXTURE_WIDTH = mDisplay.getWidth();
  23. TEXTURE_HEIGHT = mDisplay.getHeight();
  24. _memoryInfo = new MemoryInfo();
  25. activityManager = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
  26. }
  27. @Override
  28. public void onDrawFrame(GL10 gl) {
  29. synchronized (this) {
  30. surfaceTexture.updateTexImage();
  31. }
  32. activityManager.getMemoryInfo(_memoryInfo);
  33. GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
  34. GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
  35. GLES20.glEnable(GLES20.GL_BLEND);
  36. GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
  37. float[] mtx = new float[16];
  38. surfaceTexture.getTransformMatrix(mtx);
  39. mDirectDrawer.draw(mtx);
  40. calculateFps();
  41. //getAppMemorySize();
  42. //getRunningAppProcessInfo();
  43. //Log.v("onDrawFrame", "FPS: " + Math.round(fps) + ", availMem: " + Math.round(_memoryInfo.availMem / 1048576) + "MB");
  44. }
  45. private void getAppMemorySize(){
  46. ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
  47. android.os.Debug.MemoryInfo[] memoryInfos = mActivityManager.getProcessMemoryInfo(new int[]{android.os.Process.myPid()});
  48. int size = memoryInfos[0].dalvikPrivateDirty;
  49. Log.w("getAppMemorySize", size / 1024 + " MB");
  50. }
  51. private void getRunningAppProcessInfo() {
  52. ActivityManager  mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
  53. //获得系统里正在运行的所有进程
  54. List<RunningAppProcessInfo> runningAppProcessesList = mActivityManager.getRunningAppProcesses();
  55. for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcessesList) {
  56. // 进程ID号
  57. int pid = runningAppProcessInfo.pid;
  58. // 用户ID
  59. int uid = runningAppProcessInfo.uid;
  60. // 进程名
  61. String processName = runningAppProcessInfo.processName;
  62. // 占用的内存
  63. int[] pids = new int[] {pid};
  64. Debug.MemoryInfo[] memoryInfo = mActivityManager.getProcessMemoryInfo(pids);
  65. int memorySize = memoryInfo[0].dalvikPrivateDirty;
  66. System.out.println("processName="+processName+",currentPid: "+  "pid= " +android.os.Process.myPid()+"----------->"+pid+",uid="+uid+",memorySize="+memorySize+"kb");
  67. }
  68. }
  69. @Override
  70. public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  71. surface = null;
  72. surfaceTexture = null;
  73. glSurfaceTex = Engine_CreateSurfaceTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT);
  74. Log.d("GLES20Ext", "glSurfaceTex" + glSurfaceTex);
  75. if (glSurfaceTex > 0) {
  76. surfaceTexture = new SurfaceTexture(glSurfaceTex);
  77. surfaceTexture.setDefaultBufferSize(TEXTURE_WIDTH, TEXTURE_HEIGHT);
  78. surface = new Surface(surfaceTexture);
  79. addedWidgetView.setSurface(surface);
  80. addedWidgetView.setSurfaceTexture(surfaceTexture);
  81. //addedWidgetView.setSurfaceTexture(surfaceTexture);
  82. mDirectDrawer = new DirectDrawer(glSurfaceTex);
  83. }
  84. }
  85. float calculateFps() {
  86. frameCount++;
  87. if (!b) {
  88. b = true;
  89. previousTime = System.currentTimeMillis();
  90. }
  91. long intervalTime = System.currentTimeMillis() - previousTime;
  92. if (intervalTime >= 1000) {
  93. b = false;
  94. fps = frameCount / (intervalTime / 1000f);
  95. frameCount = 0;
  96. Log.w("calculateFps", "FPS: " + fps);
  97. }
  98. return fps;
  99. }
  100. int Engine_CreateSurfaceTexture(int width, int height) {
  101. /*
  102. * Create our texture. This has to be done each time the surface is
  103. * created.
  104. */
  105. int[] textures = new int[1];
  106. GLES20.glGenTextures(1, textures, 0);
  107. glSurfaceTex = textures[0];
  108. if (glSurfaceTex > 0) {
  109. GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, glSurfaceTex);
  110. // Notice the use of GL_TEXTURE_2D for texture creation
  111. GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, width, height, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, null);
  112. GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
  113. GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
  114. GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
  115. GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
  116. }
  117. return glSurfaceTex;
  118. }
  119. @Override
  120. public void onSurfaceChanged(GL10 gl, int width, int height) {
  121. }
  122. }
  1. public class DirectDrawer {
  2. private final String vertexShaderCode =
  3. "attribute vec4 vPosition;" +
  4. "attribute vec2 inputTextureCoordinate;" +
  5. "varying vec2 textureCoordinate;" +
  6. "void main()" +
  7. "{"+
  8. "gl_Position = vPosition;"+
  9. "textureCoordinate = inputTextureCoordinate;" +
  10. "}";
  11. private final String fragmentShaderCode =
  12. "#extension GL_OES_EGL_image_external : require\n"+
  13. "precision mediump float;" +
  14. "varying vec2 textureCoordinate;\n" +
  15. "uniform samplerExternalOES s_texture;\n" +
  16. "void main() {" +
  17. "  gl_FragColor = texture2D( s_texture, textureCoordinate );\n" +
  18. "}";
  19. private FloatBuffer vertexBuffer, textureVerticesBuffer;
  20. private ShortBuffer drawListBuffer;
  21. private final int mProgram;
  22. private int mPositionHandle;
  23. private int mTextureCoordHandle;
  24. private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
  25. // number of coordinates per vertex in this array
  26. private static final int COORDS_PER_VERTEX = 2;
  27. private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
  28. static float squareCoords[] = {
  29. -1.0f,  0.0f,
  30. -1.0f, -2.2f,
  31. 1.0f, -2.2f,
  32. 1.0f,  0.0f,
  33. };
  34. static float textureVertices[] = {
  35. 0f,  0f,
  36. 0f,  1f,
  37. 1f,  1f,
  38. 1f,  0f,
  39. };
  40. private int texture;
  41. public DirectDrawer(int texture)
  42. {
  43. this.texture = texture;
  44. // initialize vertex byte buffer for shape coordinates
  45. ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
  46. bb.order(ByteOrder.nativeOrder());
  47. vertexBuffer = bb.asFloatBuffer();
  48. vertexBuffer.put(squareCoords);
  49. vertexBuffer.position(0);
  50. // initialize byte buffer for the draw list
  51. ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
  52. dlb.order(ByteOrder.nativeOrder());
  53. drawListBuffer = dlb.asShortBuffer();
  54. drawListBuffer.put(drawOrder);
  55. drawListBuffer.position(0);
  56. ByteBuffer bb2 = ByteBuffer.allocateDirect(textureVertices.length * 4);
  57. bb2.order(ByteOrder.nativeOrder());
  58. textureVerticesBuffer = bb2.asFloatBuffer();
  59. textureVerticesBuffer.put(textureVertices);
  60. textureVerticesBuffer.position(0);
  61. int vertexShader    = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
  62. int fragmentShader  = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
  63. mProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program
  64. GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
  65. GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
  66. GLES20.glLinkProgram(mProgram);                  // creates OpenGL ES program executables
  67. }
  68. public void draw(float[] mtx)
  69. {
  70. GLES20.glUseProgram(mProgram);
  71. GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
  72. GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture);
  73. // get handle to vertex shader's vPosition member
  74. mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
  75. // Enable a handle to the triangle vertices
  76. GLES20.glEnableVertexAttribArray(mPositionHandle);
  77. // Prepare the <insert shape here> coordinate data
  78. GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
  79. mTextureCoordHandle = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");
  80. GLES20.glEnableVertexAttribArray(mTextureCoordHandle);
  81. // textureVerticesBuffer.clear();
  82. // textureVerticesBuffer.put( transformTextureCoordinates(
  83. // textureVertices, mtx ));
  84. // textureVerticesBuffer.position(0);
  85. GLES20.glVertexAttribPointer(mTextureCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureVerticesBuffer);
  86. GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
  87. // Disable vertex array
  88. GLES20.glDisableVertexAttribArray(mPositionHandle);
  89. GLES20.glDisableVertexAttribArray(mTextureCoordHandle);
  90. }
  91. private  int loadShader(int type, String shaderCode){
  92. // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
  93. // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
  94. int shader = GLES20.glCreateShader(type);
  95. // add the source code to the shader and compile it
  96. GLES20.glShaderSource(shader, shaderCode);
  97. GLES20.glCompileShader(shader);
  98. return shader;
  99. }
  100. private float[] transformTextureCoordinates( float[] coords, float[] matrix)
  101. {
  102. float[] result = new float[ coords.length ];
  103. float[] vt = new float[4];
  104. for ( int i = 0 ; i < coords.length ; i += 2 ) {
  105. float[] v = { coords[i], coords[i+1], 0 , 1  };
  106. Matrix.multiplyMV(vt, 0, matrix, 0, v, 0);
  107. result[i] = vt[0];
  108. result[i+1] = vt[1];
  109. }
  110. return result;
  111. }
  112. }

步骤三:配置GLSurfaceView:

  1. GLSurfaceView glSurfaceView = new GLSurfaceView(getApplicationContext());
  2. // Setup the surface view for drawing to
  3. glSurfaceView.setEGLContextClientVersion(2);
  4. glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
  5. glSurfaceView.setRenderer(renderer);
  6. //glSurfaceView.setZOrderOnTop(true);
  7. // Add our WebView to the Android View hierarchy
  8. 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的更多相关文章

  1. Android原生编解码接口 MediaCodec 之——踩坑

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/gb702250823/article/d ...

  2. 拓展 Android 原生 CountDownTimer 倒计时

    拓展 Android 原生 CountDownTimer 倒计时 [TOC] CountDownTimer 在系统的CountDownTimer上进行的修改,主要是拓展了功能,当然也保留了系统默认的模 ...

  3. android原生ExpandableListView

    android原生可扩展ExpandableListView就是可以伸缩的listView,一条标题下面有多条内容. 这个list的adapter对的数据要求与普通ListView的数据要求也有一些差 ...

  4. Android 原生listview item伸展收缩效果

    Android原生listview做的一个item的伸缩效果.*永远不要让你老大有机会改需求 package com.example.yunkanglast; import java.io.Seria ...

  5. Android原生跳转React不同页面(undefined is not an object)

    继续上篇文章的demo,由于现在的项目是原生的,打算用部分页面试下react native,那么问题来了:react貌似只有一个入口 index.android.js,那么在不同的原生页面需要跳转到不 ...

  6. android 原生camera——设置模块修改

    , 此篇博客是记一次客户需求修改,从上周五到现在正好一周时间,期间的各种酸爽,就不说了,还是来看大家关注的技术问题吧. 首先看下以前效果和修改后的效果: 修改前:修改后: 不知道有没有看明白,我在简单 ...

  7. Android进阶(二十七)Android原生扰人烦的布局

    Android原生扰人烦的布局 在开发Android应用时,UI布局是一件令人烦恼的事情.下面主要讲解一下Android中的界面布局. 一.线性布局(LinearLayout) 线性布局分为: (1) ...

  8. Android原生嵌入React Native

    1.首先集成的项目目录 我使用的是直接按照react-native init Project 的格式来导入的,也就是说,我的Android项目目录是跟node_modules是在一个目录下的. 我们i ...

  9. uni-app&H5&Android混合开发三 || uni-app调用Android原生方法的三种方式

    前言: 关于H5的调用Android原生方法的方式有很多,在该片文章中我主要简单介绍三种与Android原生方法交互的方式. 一.H5+方法调用android原生方法 H5+ Android开发规范官 ...

随机推荐

  1. Node Embedding

    1.Kipf, Thomas N., and Max Welling. "Semi-supervised classification with graph convolutional ne ...

  2. JavaScript 框架(库)

    JavaScript 高级程序设计(特别是对浏览器差异的复杂处理),通常很困难也很耗时. 为了应对这些调整,许多的 JavaScript (helper) 库应运而生. 这些 JavaScript 库 ...

  3. jvm(12)-java内存模型与线程

    [0]README 0.1)本文部分文字描述转自“深入理解jvm”,旨在学习“java内存模型与线程” 的基础知识:   [1]概述 1)并发处理的广泛应用是使得 Amdahl 定律代替摩尔定律称为计 ...

  4. staticmethod classmethod修饰符

    一.staticmethod(function) Return a static method for function.A static method does not receive an imp ...

  5. sourcenav安装

    $ ./configure之后会出现 configure: error: ./configure failed for unixconfigure: error: ./configure failed ...

  6. 笔记-Android学习历程

    1. Junit 配置:在manifest节点下 写入instrumentation,在其兄弟节点下配置application <instrumentation android:name=&qu ...

  7. MySQL索引使用:字段为varchar类型时,条件要使用''包起来

    结论: 当MySQL中字段为int类型时,搜索条件where num='111' 与where num=111都可以使用该字段的索引.当MySQL中字段为varchar类型时,搜索条件where nu ...

  8. PHPStorm2017去掉参数提示 parameter name hints

    JetBrains 的各种语言的 IDE 都灰常灰常好用, 个个都是神器, PHPStorm 作为PHP开发的神器也不必多说了 今天升级到 PHPStorm 2017.1 发现增加了好些新功能, 有个 ...

  9. sql server 2008获取表的字段注释

    SELECT 表名 then d.name else '' end, 表说明 then isnull(f.value,'') else '' end, 字段序号=a.colorder, 字段名=a.n ...

  10. 洛谷1006==codevs1169

    P1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法 ...