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())
}
}
}
网友评论