Problem with texture not showing in screen. OpenGL ES

Tags: , , ,



I am newbie in opengl es 2 programming, I was trying to load a texture in png format in my test application. I used PNGDecoder to do this, but just the black rectangle and the line are show in the screen. What is wrong?

Renderer:

@file:Suppress("NAME_SHADOWING")

package vga
import de.matthiasmann.twl.utils.PNGDecoder
import org.lwjgl.opengles.GLES20.*
import java.io.File
import org.lwjgl.BufferUtils
import org.lwjgl.opengl.GLUtil
import java.io.BufferedInputStream
import java.io.FileInputStream
import java.io.InputStream
import java.nio.Buffer
import java.nio.ByteBuffer
import kotlin.math.cos
import kotlin.math.sin


object RendererGLES {

    val vertexShader: Int
    val fragmentShader: Int
    val program: Int

    lateinit var vbosSquareIndices: IntArray
    lateinit var vbosSquareVertices: IntArray

    lateinit var vbosLine: IntArray

    val a_Position: Int

    val square: Square2D

    val textureId: Int

    val u_SamplerLocation: Int
    val a_TextCoordLocation: Int

    init
    {
        val vertexCode = File("C:\Users\cassio\Desktop\tutorial_learnopengles\seila\src\main\resources\vertex_shader.glsl").run{
            readText()
        }
        val fragmentCode = File("C:\Users\cassio\Desktop\tutorial_learnopengles\seila\src\main\resources\fragment_shader.glsl").run{
            readText()
        }

        vertexShader = compileShader(vertexCode, GL_VERTEX_SHADER)
        fragmentShader = compileShader(fragmentCode, GL_FRAGMENT_SHADER)

        program = createProgram(fragmentShader, vertexShader)

        a_Position = glGetAttribLocation(program, "a_Position")
        u_SamplerLocation = glGetUniformLocation(program, "u_Sampler")
        a_TextCoordLocation = glGetAttribLocation(program, "a_TextureCoord")
        glEnableVertexAttribArray(a_Position)

        square = Square2D(0.1f)
        glClearColor(0.8f, 0.8f, 0.8f, 1f)

        createVBOS()
        textureId = loadTexture("C:\Users\cassio\Desktop\tutorial_learnopengles\seila\src\main\resources\sla.png")

    }

    fun compileShader(code: String, type: Int): Int
    {
        val shader = glCreateShader(type)

        glShaderSource(shader, code)
        glCompileShader(shader)

        println(glGetShaderInfoLog(shader))

        return shader

    }

    fun createProgram(frag: Int, vert: Int): Int
    {
        val prog = glCreateProgram()

        glAttachShader(prog, vert)
        glAttachShader(prog, frag)

        glLinkProgram(prog)

        println(glGetProgramInfoLog(program))

        return prog
    }

    fun createVBOS()
    {

        vbosSquareVertices = IntArray(1)
        vbosSquareIndices = IntArray(1)
        vbosLine = IntArray(1)

        glGenBuffers(vbosSquareVertices)
        glBindBuffer(GL_ARRAY_BUFFER, vbosSquareVertices[0])
        glBufferData(GL_ARRAY_BUFFER, square.vertexArray, GL_STATIC_DRAW)

        glGenBuffers(vbosSquareIndices)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbosSquareIndices[0])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, square.vertexIndices, GL_STATIC_DRAW)

        glGenBuffers(vbosLine)
        glBindBuffer(GL_ARRAY_BUFFER, vbosLine[0])
        glBufferData(GL_ARRAY_BUFFER, square.line, GL_STATIC_DRAW)

    }

    fun loadTexture(fileName: String): Int {

        // Load PNG file
        val decoder = PNGDecoder(
            BufferedInputStream(FileInputStream(fileName))
        )

        // Create a big buffer to store the png data
        val buffer = ByteBuffer.allocateDirect( 4 * decoder.width * decoder.height)
        decoder.decode(buffer, decoder.width * 4, PNGDecoder.Format.RGBA)
        buffer.flip()
        val id = glGenTextures()
        glBindTexture(GL_TEXTURE_2D, id)

        // Say to opengl how unpack bytes
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, decoder.width,
            decoder.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer)

        return id
    }

    fun renderer()
    {
        glClear(GL_COLOR_BUFFER_BIT)
        glUseProgram(program)

        glActiveTexture(GL_TEXTURE0)
        glBindTexture(GL_TEXTURE_2D, textureId)

        glUniform1i(u_SamplerLocation, 0)
        square.bufferTexture.position(0)
        glBindBuffer(GL_ARRAY_BUFFER, 0)
        glVertexAttribPointer(a_TextCoordLocation, 2, GL_FLOAT, false,
                0, square.bufferTexture)

        glEnableVertexAttribArray(a_TextCoordLocation)

        glBindBuffer(GL_ARRAY_BUFFER, vbosSquareVertices[0])
        glVertexAttribPointer(a_Position, 2, GL_FLOAT, false, 0, 0)

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbosSquareIndices[0])
        nglDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)
    }    
}

Fragment Shader:

precision mediump float;

varying vec2 v_TextureCoord;
uniform sampler2D u_Sampler;

void main(){
    gl_FragColor = texture2D(u_Sampler, v_TextureCoord);
}

Vertex Shader:

attribute vec4 a_Position;
attribute vec2 a_TextureCoord;

uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;

varying vec2 v_TextureCoord;

void main() {
    v_TextureCoord = a_TextureCoord;

    gl_Position = a_Position;
    gl_PointSize = 1.0;

}

Square2D (is used to store vertex positions):

package vga

import java.nio.*
import org.lwjgl.opengles.GLES20.*

class Square2D(val size: Float) {
    val vertexArray: FloatArray
    val vertexIndices: ShortArray
    val line: FloatArray

    val textureCoordinate: FloatArray
    val bufferTexture: FloatBuffer
    init {
        line = floatArrayOf(
                -0.5f, -0.5f,
                0.5f, 0.5f
        )

        vertexArray = floatArrayOf(
                 -1f,  1f,
                 -1f, -1f,
                  1f, -1f,
                  1f,  1f,

        )

        for (i in vertexArray.indices) {
            vertexArray[i] *= size

        }

        vertexIndices = shortArrayOf(
                0, 1, 2, 2, 3, 0
        )

        textureCoordinate = floatArrayOf(
                1f,0f,
                0f,0f,
                1f,1f,
                0f,1f
        )

        for (i in textureCoordinate.indices) {
            textureCoordinate[i] *= size

        }
        bufferTexture = ByteBuffer.allocateDirect(textureCoordinate.size * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
        bufferTexture.put(textureCoordinate)
        bufferTexture.flip()
    }


}

Answer

glVertexAttribPointer can be use in 2 ways. If a named buffer object is bound, then the last argument is treated as byte offset in the buffer objects data store. If no buffer is bound (0), then the last argument is a pointer to the array data.
Hence you have to bind no buffer (0), to the GL_ARRAY_BUFFER target, before you can specify the texture coordinate attribute:

glBindBuffer(GL_ARRAY_BUFFER, 0)
glVertexAttribPointer(
    a_TextCoordLocation, 2, GL_FLOAT, false, 0, square.bufferTexture)


Source: stackoverflow