第一个的 OpenGL Render [Kotlin]
class MyRender : GLSurfaceView.Renderer {
private val TAG = "MyRender"
// Step1: 准备绘制顶点数组
// 坐标数组
// 0|3
// 1|2
private var vertexs = floatArrayOf(
-0.5f, 0.5f, 0.0f, // 长方形
// -0.8f, 0.5f, 0.0f, // 可以增加点,并改变 vertexDrawOrder 的绘制顶点数和顺序
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f
)
// 定义一个顶点的维数,即三维,三个坐标轴:x,y,z,也就是:(-0.5f, 0.5f, 0.0f) 计算为一个顶点
private val COORDINATES_PER_VERTEX = 3
// 顶点字节步长:一个顶点的字节数(native 层按字节的位置计算),也就是:(-0.5f, 0.5f, 0.0f) 的字节数
private val vertexStride = COORDINATES_PER_VERTEX * 4
// 装载 vertexs 的 buffer
// size: vertexs 的总字节数
// byte order:java是big endian,native是small endian
private var vertexBuffer: FloatBuffer? = null
// Step2: 准备绘制顶点的顺序
// 顶点顺序:指定链接坐标点的顺序
private val vertexDrawOrder = shortArrayOf(0, 1, 2, 0, 2, 3) // 绘制两个三角形,合并后看起来想正方形
// private val vertexDrawOrder = shortArrayOf(0, 1, 2) // 绘制三角形
// 装载 vertexDrawOrder 的 buffer
// size: vertexDrawOrder 的总字节数
// byte order:java是big endian,native是small endian
private var vertexDrawOrderBuffer: ShortBuffer? = null
// Step3: 准备 shader 代码
// 顶点着色程序代码
private val vertexShaderCode = """
attribute vec4 vPosition;
void main(){
gl_Position=vPosition;
}
""".trimIndent()
// 片段着色程序代码
private val fragmentShaderCode = """
precision mediump float;
uniform vec4 vColor;
void main() {
gl_FragColor = vColor;
}
""".trimIndent()
// 保存 shader 编译后的指针
private var mProgram = 0
// 顶点句柄
private var mPositionHandle: Int? = null
// 颜色句柄
private var mColorHandle: Int? = null
// Step4: 准备color
// argb
private val color = floatArrayOf(1.0f, 1.0f, 1.0f, 1.0f)
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
debug(TAG, "onSurfaceCreated:")
// Step5: 随意设置一个背景
// set default background color
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f)
// Step5: 准备顶点buffer
// vertexs buffer
val byteBuffer = ByteBuffer.allocateDirect(vertexs.size * 4)
// byte order = native order
byteBuffer.order(ByteOrder.nativeOrder())
// ByteBuffer to FloatBuffer
vertexBuffer = byteBuffer.asFloatBuffer()
// put vertexs into FloatBuffer
vertexBuffer!!.put(vertexs)
vertexBuffer!!.flip()
// Step5: 准备片段着色器buffer
// vertexDrawOrder: buffer
val byteBuffer1 = ByteBuffer.allocateDirect(vertexDrawOrder.size * 2)
// byte order = native order
byteBuffer1.order(ByteOrder.nativeOrder())
// ByteBuffer to ShortBuffer
vertexDrawOrderBuffer = byteBuffer1.asShortBuffer()
// put vertexDrawOrder into buffer
vertexDrawOrderBuffer!!.put(vertexDrawOrder)
vertexDrawOrderBuffer!!.flip()
// Step6: 加载,链接 shader 到 GLES20 program
// load vertex shader
val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
// load fragment shader
val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
// 创建一个OpenGLES程序
mProgram = GLES20.glCreateProgram()
GLES20.glAttachShader(mProgram, vertexShader)
GLES20.glAttachShader(mProgram, fragmentShader)
// 链接 Shader 到程序
GLES20.glLinkProgram(mProgram)
// 声明一个数组,用于存放链接程序结果
val linkStatus = IntArray(1)
// 获取链接程序结果,将其存入linkStatus的第0个位置
GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0)
// 链接结果处理
if (linkStatus[0] != GLES20.GL_TRUE) {
error("ES20_ERROR", "Could not link program: ")
error("ES20_ERROR", GLES20.glGetProgramInfoLog(mProgram))
GLES20.glDeleteProgram(mProgram)
mProgram = 0
}
}
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
debug(TAG, "onSurfaceChanged:")
//设置视图大小
GLES20.glViewport(0, 0, width, height)
}
override fun onDrawFrame(gl: GL10?) {
// debug(TAG, "onDrawFrame:")
// Step7: 每次绘制前清除之前的绘制
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)
if (mPositionHandle == null || mColorHandle == null) {
// Step8: 运行 GLES20 program 进行绘制
// 将程序加入到OpenGLES环境
GLES20.glUseProgram(mProgram)
// 获取顶点着色器的句柄: shader 中的定义变量
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition")
//启用句柄
GLES20.glEnableVertexAttribArray(mPositionHandle!!)
//填入数据
GLES20.glVertexAttribPointer(
mPositionHandle!!, COORDINATES_PER_VERTEX, GLES20.GL_FLOAT,
false, vertexStride, vertexBuffer
)
//获取顶点着色器的句柄: shader 中的定义变量
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor")
//填入数据
GLES20.glUniform4fv(mColorHandle!!, 1, color, 0)
}
//开始绘制:用三个顶点(vertexCount)画一个三角形(GL_TRIANGLES)
// GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount)
GLES20.glDrawElements(
GLES20.GL_TRIANGLE_STRIP, vertexDrawOrder.size,
GLES20.GL_UNSIGNED_SHORT, vertexDrawOrderBuffer
)
// 禁用顶点着色器的句柄【disable 后需要重新 enable 才能继续绘制】
// GLES20.glDisableVertexAttribArray(mPositionHandle!!)
}
fun loadShader(type: Int, shaderCode: String): Int { //根据类型创建着色器
var shader = GLES20.glCreateShader(type)
//加入代码
GLES20.glShaderSource(shader, shaderCode)
//开始编译
GLES20.glCompileShader(shader)
//声明一个数组,用于存放编译结果
val compiled = IntArray(1)
//获取编译结果,将其存入到compiled的第0个位置中
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0)
//根据编译结果做处理
if (compiled[0] == 0) {
error("ES20_ERROR", "Could not compile shader $type : $shaderCode")
error("ES20_ERROR", GLES20.glGetShaderInfoLog(shader))
GLES20.glDeleteShader(shader)
shader = 0
}
return shader
}
}
网友评论