I successfully followed this guide to draw a triangle with OpenGL, and now I'm trying to modify the code to draw a circle. The tutorial didn't instruct me how to do this so I tried using the code from here, halfway down the page under "For your toolbox." The approach I'm taking is to define a square in OpenGL, then like what was suggested here, use the fragment shader to draw a circle within the square. Here's the code I have for the Circle class:
package com.example.onwards
import android.content.res.Resources
import android.opengl.GLES30
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
class Circle {
private val vertexCoords = floatArrayOf(
-0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f // top right
)
private val resolution = floatArrayOf(
getScreenWidth().toFloat(),
getScreenHeight().toFloat()
)
private val vertexShaderCode =
""" |attribute vec4 vPosition;
|void main() {
| gl_Position = vPosition;
|}
|""".trimMargin()
private val fragmentShaderCode =
""" |precision mediump float;
|
|uniform vec2 vResolution;
|
|float circle(in vec2 st, in float r) {
| vec2 dist = st - vec2(0.5);
| return 1. - step(r * r, dot(dist, dist));
|}
|
|void main() {
| vec2 st = gl_FragCoord.xy / vResolution.xy;
| vec3 color = vec3(circle(st, 0.5));
| // TODO: Set alpha to 0 outside of circle
| gl_FragColor = vec4(color, 1.);
|}
|""".trimMargin()
private val vertexBuffer: FloatBuffer =
ByteBuffer.allocateDirect(vertexCoords.size * 4).run {
order(ByteOrder.nativeOrder())
asFloatBuffer().apply {
put(vertexCoords)
position(0)
}
}
private val vertexCount: Int = vertexCoords.size / COORDS_PER_VERTEX
private val vertexStride: Int = COORDS_PER_VERTEX * 4
private var program: Int
private var positionHandle: Int = 0
init {
val vertexShader: Int = loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader: Int = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode)
program = GLES30.glCreateProgram().also {
GLES30.glAttachShader(it, vertexShader)
GLES30.glAttachShader(it, fragmentShader)
GLES30.glLinkProgram(it)
}
}
private fun loadShader(type: Int, shaderCode: String): Int {
return GLES30.glCreateShader(type).also { shader ->
GLES30.glShaderSource(shader, shaderCode)
GLES30.glCompileShader(shader)
}
}
private fun getScreenWidth(): Int {
return Resources.getSystem().displayMetrics.widthPixels
}
private fun getScreenHeight(): Int {
return Resources.getSystem().displayMetrics.heightPixels
}
fun draw() {
GLES30.glUseProgram(program)
positionHandle = GLES30.glGetAttribLocation(program, "vPosition").also {
GLES30.glEnableVertexAttribArray(it)
GLES30.glVertexAttribPointer(
it,
COORDS_PER_VERTEX,
GLES30.GL_FLOAT,
false,
vertexStride,
vertexBuffer
)
GLES30.glGetUniformLocation(program, "vResolution").also { resHandle ->
GLES30.glUniform2fv(resHandle, 1, resolution, 0)
}
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount)
GLES30.glDisableVertexAttribArray(it)
}
}
}
However, running the app only yields a white triangle in the center of the screen. Its vertices are in the top left, bottom left, and lower right, so it seems like OpenGL is drawing only one of the triangles required for the square.
I noticed that the drawOrder and drawListBuffer variables from this section were never used in the next part of the tutorial; they only focused on drawing the triangle and not the square. Maybe that has something to do with it?