美文网首页
Android OpenGL ES 绘制图片

Android OpenGL ES 绘制图片

作者: 雁过留声_泪落无痕 | 来源:发表于2021-09-16 16:57 被阅读0次
class ShaderTestActivity : AppCompatActivity() {

    companion object {
        private const val TAG = "hehe"
    }

    private lateinit var mGLSurfaceView: GLSurfaceView
    private lateinit var mBitmap: Bitmap

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mGLSurfaceView = GLSurfaceView(this)
        setContentView(mGLSurfaceView)
        initGLSurfaceView()
        initBitmap()
    }

    private fun initGLSurfaceView() {
        mGLSurfaceView.setEGLContextClientVersion(2)
        mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0)
        mGLSurfaceView.setRenderer(object : GLSurfaceView.Renderer {
            override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
                GLES20.glClearColor(0f, 0f, 0f, 0f)

                initPosition()
                initTextureCoordinate()
                createProgram()
                activeTexture()
            }

            override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
                GLES20.glViewport(0, 0, width, height)
            }

            override fun onDrawFrame(gl: GL10?) {
                GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
                mGLSurfaceView.requestRender()

                draw()
            }
        })
        mGLSurfaceView.renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
    }

    override fun onDestroy() {
        super.onDestroy()
        release()
    }

    private fun initBitmap() {
        mBitmap = BitmapFactory.decodeResource(resources, R.drawable.tree)
    }

    private val mVertexShader = """
        attribute vec4 position;
        attribute vec2 inputTextureCoordinate;
        varying vec2 textureCoordinate;
        
        void main() {
            textureCoordinate = inputTextureCoordinate;
            gl_Position = position; 
        }
    """.trimIndent()

    private val mFragmentShader = """
        precision mediump float;
        
        uniform sampler2D inputImageTexture;
        varying vec2 textureCoordinate;
        
        void main() {
            gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
        }
    """.trimIndent()

    private var mTextureId = -1
    private var mProgram = -1

    private var mPositionHandle = -1
    private var mTextureCoordinateHandle = -1
    private var mImageTextureHandle = -1

    private lateinit var mPositionBuffer: FloatBuffer
    private lateinit var mTextureCoordinateBuffer: FloatBuffer

    private fun initPosition() {
        val vertexPosition = floatArrayOf(
            -1f, -1f, // left-down
            +1f, -1f, // right-down
            -1f, +1f, // left-up
            +1f, +1f, // right-up
        )

        ByteBuffer.allocateDirect(vertexPosition.size * 4).apply {
            order(ByteOrder.nativeOrder())
            mPositionBuffer = asFloatBuffer()
        }
        mPositionBuffer.put(vertexPosition)
        mPositionBuffer.position(0)
    }

    private fun initTextureCoordinate() {
        val textureCoordinate = floatArrayOf(
            0f, 1f, // left-down
            1f, 1f, // right-down
            0f, 0f, // left-up
            1f, 0f, // right-up
        )

        ByteBuffer.allocateDirect(textureCoordinate.size * 4).apply {
            order(ByteOrder.nativeOrder())
            mTextureCoordinateBuffer = asFloatBuffer()
        }
        mTextureCoordinateBuffer.put(textureCoordinate)
        mTextureCoordinateBuffer.position(0)
    }

    private fun createProgram() {
        // 创建 vertex shader
        val vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER)
        GLES20.glShaderSource(vertexShaderHandle, mVertexShader)
        GLES20.glCompileShader(vertexShaderHandle)
        checkError()

        // 创建 fragment shader
        val fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER)
        GLES20.glShaderSource(fragmentShaderHandle, mFragmentShader)
        GLES20.glCompileShader(fragmentShaderHandle)
        checkError()

        // 创建 program
        mProgram = GLES20.glCreateProgram()
        GLES20.glAttachShader(mProgram, vertexShaderHandle)
        GLES20.glAttachShader(mProgram, fragmentShaderHandle)
        GLES20.glLinkProgram(mProgram)
        checkError()

        // 读取变量 location
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "position")
        mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate")
        mImageTextureHandle = GLES20.glGetUniformLocation(mProgram, "inputImageTexture")

        // 删除 shader
        GLES20.glDeleteShader(vertexShaderHandle)
        GLES20.glDeleteShader(fragmentShaderHandle)
        checkError()
    }

    private fun activeTexture() {
        // 生成纹理
        val array = IntArray(1)
        GLES20.glGenTextures(1, array, 0)
        mTextureId = array[0]

        // 激活纹理并设置过滤模式
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId)
        GLES20.glTexParameterf(
            GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_MIN_FILTER,
            GLES20.GL_LINEAR.toFloat()
        )
        GLES20.glTexParameterf(
            GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_MAG_FILTER,
            GLES20.GL_LINEAR.toFloat()
        )
        GLES20.glTexParameteri(
            GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_WRAP_S,
            GLES20.GL_CLAMP_TO_EDGE
        )
        GLES20.glTexParameteri(
            GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_WRAP_T,
            GLES20.GL_CLAMP_TO_EDGE
        )
        checkError()
    }

    private fun draw() {
        // 启动 mProgram
        GLES20.glUseProgram(mProgram)

        // 使能 mPositionHandle 并传值
        GLES20.glEnableVertexAttribArray(mPositionHandle)
        GLES20.glVertexAttribPointer(
            mPositionHandle,
            2,
            GLES20.GL_FLOAT,
            false,
            0,
            mPositionBuffer
        )

        // 使能 mTextureCoordinateHandle 并传值
        GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle)
        GLES20.glVertexAttribPointer(
            mTextureCoordinateHandle,
            2,
            GLES20.GL_FLOAT,
            false,
            0,
            mTextureCoordinateBuffer
        )

        // 使能 mImageTextureHandle 并传值
        GLES20.glUniform1i(mImageTextureHandle, 0)

        // 传递纹理数据
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0)

        // 绘制
        // GL_TRIANGLES: 以 0,1,2 3,4,5 ... 的形式绘制三角形
        // GL_TRIANGLE_FAN: 以 2,1,0 3,2,0 4,3,0 5,4,0 ... 的形式绘制三角形,
        //                  即从第三个顶点开始,该顶点+前一个顶点+第0个顶点一次组成三角形绘制
        // GL_TRIANGLE_STRIP: 以 0,1,2 1,2,3 2,3,4 ... 的形式绘制三角形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
    }

    private fun release() {
        GLES20.glDisableVertexAttribArray(mPositionHandle)
        GLES20.glDisableVertexAttribArray(mTextureCoordinateHandle)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, GLES20.GL_NONE)
        GLES20.glDeleteTextures(1, intArrayOf(mTextureId), 0)
        GLES20.glDeleteProgram(mProgram)
    }

    private fun checkError() {
        val errorCode = GLES20.glGetError()
        if (errorCode > 0) {
            Log.d(TAG, "errorCode: $errorCode", Throwable())
        }
    }

}

相关文章

网友评论

      本文标题:Android OpenGL ES 绘制图片

      本文链接:https://www.haomeiwen.com/subject/ckzrgltx.html