Geometry is rendering fine and works with attribute colors so I've definitely got something wrong with my texture loading / usage code. I've been following along with the tutorials at learnopengl.com as best I can. The code below is in Kotlin, so despite the funky syntax all the objects are standard Java objects. (While it should hopefully be easy enough to follow I've added some additional comments to the less obvious stuff.)
Initialisation:
glClearColor(1f, 0f, 0f, 1f)
// these will be overridden further on. (var is mutable, val is not)
var vao = -1
var vbo = -1
var ebo = -1
var texture = -1
var shaderProgram = -1
{ // Set up the geometry. A simple quad.
val vertexBuffer = BufferUtils.createFloatBuffer(4 * 8) // 4 vertices of 8 floats.
// position color uv
vertexBuffer.put(floatArrayOf(-0.5f, -0.5f, 0f, 1f, 0f, 0f, 0f, 0f))
vertexBuffer.put(floatArrayOf( 0.5f, -0.5f, 0f, 0f, 1f, 0f, 1f, 0f))
vertexBuffer.put(floatArrayOf( 0.5f, 0.5f, 0f, 0f, 0f, 1f, 1f, 1f))
vertexBuffer.put(floatArrayOf(-0.5f, 0.5f, 0f, 1f, 1f, 1f, 0f, 1f))
vertexBuffer.flip()
val indexBuffer = BufferUtils.createIntBuffer(3 * 2)
indexBuffer.put(intArrayOf(0, 1, 2))
indexBuffer.put(intArrayOf(2, 3, 0))
indexBuffer.flip()
vao = glGenVertexArrays()
vbo = glGenBuffers()
ebo = glGenBuffers()
glBindVertexArray(vao)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, false, 8 * 4, 0)
glEnableVertexAttribArray(0)
glVertexAttribPointer(1, 3, GL_FLOAT, false, 8 * 4, 3 * 4)
glEnableVertexAttribArray(1)
glVertexAttribPointer(2, 2, GL_FLOAT, false, 8 * 4, 6 * 4)
glEnableVertexAttribArray(2)
glBindVertexArray(0)
}
{ // load the texture
val image = ImageIO.read(File("test_image.png"))
val pixels = IntArray(image.width * image.height) //image.width corresponds to image.getWidth() in Java, same for height.
image.getRGB(0, 0, image.width, image.height, pixels, 0, image.width)
val buffer = BufferUtils.createByteBuffer(image.width * image.height * 4)
var y = 0
var x = 0
while (y < image.height) {
while (x < image.width) {
val pixel = pixels[y * image.width + x]
buffer.put(((pixel shr 16) and 0xFF).toByte()) // "shr" and "and" are the usual ">>" and "&" bitwise operators.
buffer.put(((pixel shr 8) and 0xFF).toByte())
buffer.put((pixel and 0xFF).toByte())
buffer.put(((pixel shr 24) and 0xFF).toByte())
x++
}
x = 0
y++
}
buffer.flip()
texture = glGenTextures()
glBindTexture(GL_TEXTURE_2D, texture)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer)
glBindTexture(GL_TEXTURE_2D, 0)
}
{ // set up the shader
val vertexSource = """
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 uv;
out vec3 vColor;
out vec2 vUv;
void main() {
vColor = color;
vUv = uv;
gl_Position = vec4(position, 1.0);
}
"""
val vertexShader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertexShader, vertexSource)
glCompileShader(vertexShader)
val fragmentSource = """
#version 330 core
precision highp float;
in vec3 vColor;
in vec2 vUv;
out vec4 color;
uniform sampler2D texSampler;
void main(){
color = texture(texSampler, vUv);
// color = vec4(vColor, 1.0);
}
"""
val shader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragmentShader, fragmentSource)
glCompileShader(fragmentShader)
shaderProgram = glCreateProgram()
glAttachShader(shaderProgram, vertexShader)
glAttachShader(shaderProgram, fragmentShader)
glLinkProgram(shaderProgram)
glDeleteShader(vertexShader)
glDeleteShader(fragmentShader)
}
Then when rendering:
glClear(GL_COLOR_BUFFER_BIT)
glUseProgram(shader)
glBindTexture(GL_TEXTURE_2D, texture)
glBindVertexArray(vao)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)
glBindVertexArray(0)
If the commented line in the fragment shader is swapped in it renders the colored quad as expected, but it just renders black when trying to use the texture. Stepping through the code in the debugger shows that the pixel colors being added to the texture buffer are colored as expected.
I've also got additional error checking in the shader loading and in the main loop, but as far as I can see OpenGL isn't showing any errors.