2011-11-22 17 views
21

El TextureView documentation indica que se puede usar para representar contenido OpenGL.Cómo reemplazar GLSurfaceView con TextureView en Android Ice Cream Sandwich?

En el blog post anunciando TextureView, se indica:

Un TextureView puede ser tan fácilmente utilizado para incrustar una escena OpenGL en su aplicación. A partir de Android 4.0, eglCreateWindowSurface() se puede utilizar para representar en un objeto SurfaceTexture.

que parece dar a entender que para usar en lugar de TextureView GLSurfaceView, habría que hacer todo de la configuración de EGL sí mismos y gestionar el EGLContext y la rosca (ya que mantiene un GLSurfaceView GLTHREAD). No parece haber ningún código de muestra en el SDK de Android 4.0 que demuestre cómo el "TextureView se puede usar fácilmente para incrustar una escena de OpenGL". TextureView parece conectarse más limpiamente a la vista previa de la cámara (setPreviewTexture) y MediaPlayer (setSurface).

¿Es posible usar GLSurfaceView junto con TextureView usando GLSurfaceView.setEGLWindowSurfaceFactory para hacer que se represente en TextureTexture de TextureView?

Nuevamente, sería bueno si hubiera algún código de muestra.

+3

Fwiw, varios ejemplos se pueden encontrar en Grafika (https://github.com/google/grafika). Para obtener información adicional, consulte https://source.android.com/devices/graphics.html. – fadden

+0

Esta es una gran publicación de discusión al respecto: https://groups.google.com/forum/m/#!topic/android-developers/U5RXFGpAHPE –

Respuesta

1

Un moderador elimina esta respuesta lo que la adición de nuevo para la posteridad:

Véase la respuesta de Romain individuo (noviembre 23ra 2011) del grupo google android-dev:

http://groups.google.com/group/android-developers/browse_thread/thread/539457146a401cf1 (duplicado: http://grokbase.com/t/gg/android-developers/11bqmgb7sw/how-to-replace-glsurfaceview-with-textureview-in-android-ice-cream-sandwich)

GLSurfaceView maneja la configuración GL para usted, que TextureView no hará. Un TextureView se puede utilizar como la ventana nativa al crear una superficie EGL . Aquí hay un ejemplo (la parte interesante es la llamada a eglCreateWindowSurface()):

@Override 
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 
    mRenderThread = new RenderThread(getResources(), surface); 
    mRenderThread.start(); 
} 

private static class RenderThread extends Thread { 
    private static final String LOG_TAG = "GLTextureView"; 

    static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 
    static final int EGL_OPENGL_ES2_BIT = 4; 

    private volatile boolean mFinished; 

    private final Resources mResources; 
    private final SurfaceTexture mSurface; 

    private EGL10 mEgl; 
    private EGLDisplay mEglDisplay; 
    private EGLConfig mEglConfig; 
    private EGLContext mEglContext; 
    private EGLSurface mEglSurface; 
    private GL mGL; 

    RenderThread(Resources resources, SurfaceTexture surface) { 
     mResources = resources; 
     mSurface = surface; 
    } 

    private static final String sSimpleVS = 
      "attribute vec4 position;\n" + 
      "attribute vec2 texCoords;\n" + 
      "varying vec2 outTexCoords;\n" + 
      "\nvoid main(void) {\n" + 
      " outTexCoords = texCoords;\n" + 
      " gl_Position = position;\n" + 
      "}\n\n"; 
    private static final String sSimpleFS = 
      "precision mediump float;\n\n" + 
      "varying vec2 outTexCoords;\n" + 
      "uniform sampler2D texture;\n" + 
      "\nvoid main(void) {\n" + 
      " gl_FragColor = texture2D(texture, outTexCoords);\n" + 
      "}\n\n"; 

    private static final int FLOAT_SIZE_BYTES = 4; 
    private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; 
    private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; 
    private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; 
    private final float[] mTriangleVerticesData = { 
      // X, Y, Z, U, V 
      -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 
       1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 
      -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 
       1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 
    }; 

    @Override 
    public void run() { 
     initGL(); 

     FloatBuffer triangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
     triangleVertices.put(mTriangleVerticesData).position(0); 

     int texture = loadTexture(R.drawable.large_photo); 
     int program = buildProgram(sSimpleVS, sSimpleFS); 

     int attribPosition = glGetAttribLocation(program, "position"); 
     checkGlError(); 

     int attribTexCoords = glGetAttribLocation(program, "texCoords"); 
     checkGlError(); 

     int uniformTexture = glGetUniformLocation(program, "texture"); 
     checkGlError(); 

     glBindTexture(GL_TEXTURE_2D, texture); 
     checkGlError(); 

     glUseProgram(program); 
     checkGlError(); 

     glEnableVertexAttribArray(attribPosition); 
     checkGlError(); 

     glEnableVertexAttribArray(attribTexCoords); 
     checkGlError(); 

     glUniform1i(uniformTexture, texture); 
     checkGlError(); 

     while (!mFinished) { 
      checkCurrent(); 

      glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 
      checkGlError(); 

      glClear(GL_COLOR_BUFFER_BIT); 
      checkGlError(); 

      // drawQuad 

      triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); 
      glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false, 
        TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 

      triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); 
      glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false, 
        TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 

      glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 

      if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { 
       throw new RuntimeException("Cannot swap buffers"); 
      } 
      checkEglError(); 

      try { 
       Thread.sleep(2000); 
      } catch (InterruptedException e) { 
       // Ignore 
      } 
     } 

     finishGL(); 
    } 

    private int loadTexture(int resource) { 
     int[] textures = new int[1]; 

     glActiveTexture(GL_TEXTURE0); 
     glGenTextures(1, textures, 0); 
     checkGlError(); 

     int texture = textures[0]; 
     glBindTexture(GL_TEXTURE_2D, texture); 
     checkGlError(); 

     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

     Bitmap bitmap = BitmapFactory.decodeResource(mResources, resource); 

     GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0); 
     checkGlError(); 

     bitmap.recycle(); 

     return texture; 
    } 

    private int buildProgram(String vertex, String fragment) { 
     int vertexShader = buildShader(vertex, GL_VERTEX_SHADER); 
     if (vertexShader == 0) return 0; 

     int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 
     if (fragmentShader == 0) return 0; 

     int program = glCreateProgram(); 
     glAttachShader(program, vertexShader); 
     checkGlError(); 

     glAttachShader(program, fragmentShader); 
     checkGlError(); 

     glLinkProgram(program); 
     checkGlError(); 

     int[] status = new int[1]; 
     glGetProgramiv(program, GL_LINK_STATUS, status, 0); 
     if (status[0] != GL_TRUE) { 
      String error = glGetProgramInfoLog(program); 
      Log.d(LOG_TAG, "Error while linking program:\n" + error); 
      glDeleteShader(vertexShader); 
      glDeleteShader(fragmentShader); 
      glDeleteProgram(program); 
      return 0; 
     } 

     return program; 
    } 

    private int buildShader(String source, int type) { 
     int shader = glCreateShader(type); 

     glShaderSource(shader, source); 
     checkGlError(); 

     glCompileShader(shader); 
     checkGlError(); 

     int[] status = new int[1]; 
     glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0); 
     if (status[0] != GL_TRUE) { 
      String error = glGetShaderInfoLog(shader); 
      Log.d(LOG_TAG, "Error while compiling shader:\n" + error); 
      glDeleteShader(shader); 
      return 0; 
     } 

     return shader; 
    } 

    private void checkEglError() { 
     int error = mEgl.eglGetError(); 
     if (error != EGL10.EGL_SUCCESS) { 
      Log.w(LOG_TAG, "EGL error = 0x" + Integer.toHexString(error)); 
     } 
    } 

    private void checkGlError() { 
     int error = glGetError(); 
     if (error != GL_NO_ERROR) { 
      Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error)); 
     } 
    } 

    private void finishGL() { 
     mEgl.eglDestroyContext(mEglDisplay, mEglContext); 
     mEgl.eglDestroySurface(mEglDisplay, mEglSurface); 
    } 

    private void checkCurrent() { 
     if (!mEglContext.equals(mEgl.eglGetCurrentContext()) || 

     !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) { 
      if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 
       throw new RuntimeException("eglMakeCurrent failed " + GLUtils.getEGLErrorString(mEgl.eglGetError())); 
      } 
     } 
    } 

    private void initGL() { 
     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)) { 
      throw new RuntimeException("eglInitialize failed " + 
        GLUtils.getEGLErrorString(mEgl.eglGetError())); 
     } 

     mEglConfig = chooseEglConfig(); 
     if (mEglConfig == null) { 
      throw new RuntimeException("eglConfig not initialized"); 
     } 

     mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); 

     mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null); 

     if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) 
     { 
      int error = mEgl.eglGetError(); 
      if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { 
       Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 
       return; 
      } 
      throw new RuntimeException("createWindowSurface failed " 
        + GLUtils.getEGLErrorString(error)); 
     } 

     if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 
      throw new RuntimeException("eglMakeCurrent failed " 
        + GLUtils.getEGLErrorString(mEgl.eglGetError())); 
     } 

     mGL = mEglContext.getGL(); 
    } 


    EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 
     int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; 
     return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); 
    } 

    private EGLConfig chooseEglConfig() { 
     int[] configsCount = new int[1]; 
     EGLConfig[] configs = new EGLConfig[1]; 
     int[] configSpec = getConfig(); 
     if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) { 
      throw new IllegalArgumentException("eglChooseConfig failed " + 
        GLUtils.getEGLErrorString(mEgl.eglGetError())); 
     } else if (configsCount[0] > 0) { 
      return configs[0]; 
     } 
     return null; 
    } 

    private int[] getConfig() { 
     return new int[] { 
       EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 
       EGL10.EGL_RED_SIZE, 8, 
       EGL10.EGL_GREEN_SIZE, 8, 
       EGL10.EGL_BLUE_SIZE, 8, 
       EGL10.EGL_ALPHA_SIZE, 8, 
       EGL10.EGL_DEPTH_SIZE, 0, 
       EGL10.EGL_STENCIL_SIZE, 0, 
       EGL10.EGL_NONE 
     }; 
    } 

    void finish() { 
     mFinished = true; 
    } 
} 
Cuestiones relacionadas