zoukankan      html  css  js  c++  java
  • 把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 绘制自己:

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. setWillNotDraw(false);  

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

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. private void addOnPreDrawListener() {  
    2.   
    3.     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {  
    4.   
    5.         final ViewTreeObserver mObserver = getViewTreeObserver();  
    6.         if (mObserver != null) {  
    7.             mObserver.addOnPreDrawListener(new OnPreDrawListener() {  
    8.   
    9.                 @Override  
    10.                 public boolean onPreDraw() {  
    11.                     if (isDirty()) {//View或者子view发生变化  
    12.                         invalidate();  
    13.                     }  
    14.                     return true;  
    15.                 }  
    16.             });  
    17.         }  
    18.     }  
    19. }  

     3.重写该View的onDraw方法:

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    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.               
    9.             mSurface.release();  
    10.             mSurface = null;  
    11.             mSurface = new Surface(mSurfaceTexture);  
    12.         }  
    13.     } catch (OutOfResourcesException e) {  
    14.         e.printStackTrace();  
    15.     }  
    16. }  

    步骤二:GLSurfaceView.Renderer

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

    步骤三:配置GLSurfaceView:

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. GLSurfaceView glSurfaceView = new GLSurfaceView(getApplicationContext());  
    2. // Setup the surface view for drawing to  
    3.   
    4. glSurfaceView.setEGLContextClientVersion(2);  
    5. glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);         
    6. glSurfaceView.setRenderer(renderer);  
    7. //glSurfaceView.setZOrderOnTop(true);  
    8.   
    9. // Add our WebView to the Android View hierarchy  
    10. 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

  • 相关阅读:
    oracelp---随意 记录(nvl)
    delphi小知识 点(if条件符,to_date)
    截取字符(pos,copy,Leftstr,MidStr,RightStr)以逗号为准把字符串拆分,判断字符串是否有数字、字母(大小写), 去掉字符串空格
    js HTML DOM TableRow 对象(innerHTML)
    mysql 安装相关
    初识JAVAScript
    css
    css深入
    css的学习
    前端 html
  • 原文地址:https://www.cnblogs.com/jukan/p/6846947.html
Copyright © 2011-2022 走看看