Texture is not rendering (renders black)

Hi,

I’m starting using OpenGL for an Android project as the task I am doing requires OpenGL.
Using OpenGL ES 2.0 on Android 7. I’m trying to draw a texture as a test but it’s just rendering black:[ATTACH=CONFIG]1777[/ATTACH]

texture: [ATTACH=CONFIG]1778[/ATTACH]

glGetError returns 0, shader compiles, other examples don’t seem to do anything different…I’m out of options.
Need to clean up some of the code including writing a custom log function, so don’t be confused by that.
Error is likely somewhere at glTexture2D where I create the texture. I can verify that the shader and textureVertices array works, if I take out the texture2D function in the Fragment shader it is working.
Thank you for your time.
Here is my code, it’s just lots as the error could be anywhere:

Fragment Shader:

#version 100
precision mediump float;

varying vec3 Color;
varying vec2 Texcoord;

uniform sampler2D tex;


void main()
{
gl_FragColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);
} 

Vertex Shader:

#version 100
attribute vec2 position;
attribute vec3 color;
attribute vec2 texcoord;

varying vec3 Color;
varying vec2 Texcoord;


void main()
{

gl_Position = vec4(position, 0.0, 1.0);
Color = color;
Texcoord = texcoord;
}

fileManager.cpp:


...
const char* FileManager::ReadFile(const char *path, off_t& length)
{
    AAsset* asset=AAssetManager_open(FileManager::assetManager,path,AASSET_MODE_BUFFER);

    char* buff = new char[AAsset_getLength(asset)];
    length = AAsset_getLength(asset);
    AAsset_read(asset,buff,(size_t)length);
    AAsset_close(asset);
    return buff;
}

texture2d.cpp:

#include "texture2D.h"
#include "defines.h"
#if defined(OPENGL)
#include "gl/glTexture2D.h"
#endif



shared_ptr<Texture2D>  Texture2D::Load(string &location) {
#if defined(OPENGL)
    return shared_ptr<Texture2D>(new GlTexture2D(location));
#endif
}

glTexture2D.h:

#pragma once

#include <GLES2/gl2.h>
#include "../texture2D.h"

class GlTexture2D : public Texture2D {

private:
    GLuint texture;
    static constexpr float textureVertices[] = {
//          Position      Color             Texcoords
            -0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Top-left
            0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Top-right
            0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // Bottom-right
            -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f  // Bottom-left
    };


    static constexpr GLuint elements[] = { 0, 1, 2, 2, 3, 0 };

    static GLuint shaderProgram;

    GLuint ebo;

public:
    GlTexture2D(string& path);
    void Draw() override ;
};

glTexture2D.cpp:



#include <cstdlib>
#include <android/log.h>

#include "glTexture2D.h"
#include "pngLoader.h"
#include "../fileManager.h"
#include "../openGLRenderer.h"
#include "glHelper.h"

using namespace std;

constexpr float GlTexture2D::textureVertices[28];
constexpr GLuint GlTexture2D::elements[6];
GLuint GlTexture2D::shaderProgram;


GlTexture2D::GlTexture2D (string& path)
{
    int32_t length = (int32_t)path.length();
    string extension = "";
    for (int i = length-1;i >= 0;--i)
    {
        char letter = path[i];
        extension = letter+extension;

        if(letter == '.')
            break;
    }

    if(extension != ".png")
    {
        printf("Error. Can only load PNG textures.");
        return;
    }

    int width, height;
    GLint format;
    const void* data = NULL;

    data = PngLoader::loadPng(path.c_str(),width,height, format);
    if(data == NULL)
    {
        printf("Error. PNGLoader could not load png file.");
        return;
    }





    GLuint vbo;
    // Generate 1 vertex buffer
    glGenBuffers(1, &vbo);
    // Bind the buffer (tell the buffer what type of buffer it is)
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // Copy vertex data to our array buffer (note how we reference it by GL_ARRAY_BUFFER, NOT the vbo int
    glBufferData(GL_ARRAY_BUFFER, sizeof(GlTexture2D::textureVertices), GlTexture2D::textureVertices, GL_STATIC_DRAW);


    // generate 1 element buffer
  // connection?
    glGenBuffers(1, &ebo);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GlTexture2D::elements), GlTexture2D::elements, GL_STATIC_DRAW);

    // Load shader



   GLuint result = GlHelper::loadShader((char*)"openGLShader/default.frag",(char*)"openGLShader/default.vert");
    if(!result)
    {
        printf("Shader compile fail");
        return;
    }
    shaderProgram = result;



    // Generate the OpenGL texture object

    glGenTextures(1, &texture);





   //float pixels[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
   //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_FLOAT, pixels);

    glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    GLint loc = glGetUniformLocation (shaderProgram,"tex");
    glUniform1i(loc,0);

    //glGenerateMipmap(GL_TEXTURE_2D);



    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);



    //free((char*)data);
}

void GlTexture2D ::Draw()
{

 glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT, nullptr);
}

glHelper.cpp:



#include "glHelper.h"
#include "../fileManager.h"
#include "../openGLRenderer.h"
#include <android/log.h>
#include <sys/types.h>

GLuint GlHelper::loadShader(char* fragment, char* vertical)
{
    off_t fLength;
    const char *vertexSource = FileManager::ReadFile(vertical,fLength);

    //fReader.ReadAll(vertexSourcePath);
    // Create vertex shader
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexSource, NULL);
    glCompileShader(vertexShader);


    GLint status; GLint logLength;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);



    if (status != GL_TRUE)
    {

        glGetShaderiv(vertexShader,GL_INFO_LOG_LENGTH,&logLength);
        char buffer[logLength];
        glGetShaderInfoLog(vertexShader, logLength, NULL, buffer);


        // Reason for %s formating: https://stackoverflow.com/questions/9306175/how-to-fix-this-compiler-error-format-not-a-string-literal-and-no-format-argume
        // A char buffer can't be applied with specifying it to avoid potential security leak.
        __android_log_print(ANDROID_LOG_ERROR, QS_OPENGLTAG, "%s",buffer);
        // Shader compile fail.

        return 0;
    }

    off_t fLength2;
    const char *fragmentSource = FileManager::ReadFile(fragment,fLength2);

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader,GL_COMPILE_STATUS, &status);



    if (status != GL_TRUE)
    {

        glGetShaderiv(fragmentShader,GL_INFO_LOG_LENGTH,&logLength);
        char buffer[logLength];
        glGetShaderInfoLog(fragmentShader, logLength, NULL, buffer);


        // Shader compile fail.
        __android_log_print(ANDROID_LOG_ERROR, QS_OPENGLTAG,"%s", buffer);
        return 0;
    }

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);

    // OpenGL ES only supports 1 vertex shader output. The following line is nessesary if you had more than 1 outputs in normal openGL
    //glBindFragDataLocation(shaderProgram, 0, "outColor");

    // Link the shaders



    glLinkProgram(shaderProgram);


    glGetProgramiv(shaderProgram,GL_LINK_STATUS,&status);


    if(status != GL_TRUE)
    {
        glGetProgramiv(shaderProgram,GL_INFO_LOG_LENGTH,&logLength);
        char buffer[logLength];
        glGetProgramInfoLog(shaderProgram,logLength,NULL,buffer);
        __android_log_print(ANDROID_LOG_ERROR,QS_OPENGLTAG,"%s",buffer);
        return 0;
    }

    // Validate and error check.
    glValidateProgram(shaderProgram);


    glGetProgramiv(shaderProgram, GL_VALIDATE_STATUS, &status);
    if(status != GL_TRUE)
    {
        glGetProgramiv(shaderProgram,GL_INFO_LOG_LENGTH,&logLength);
        char buffer[logLength];
        glGetProgramInfoLog(shaderProgram,logLength,NULL,buffer);
        __android_log_print(ANDROID_LOG_ERROR,QS_OPENGLTAG,"%s",buffer);
        return 0;
    }

    glUseProgram(shaderProgram);

    GLenum  err = glGetError();
    if(err != GL_NO_ERROR)
    {
        __android_log_print(ANDROID_LOG_ERROR,QS_OPENGLTAG,"%s","OpenGL error code: "); // + to_string((int)err));
        return 0;
    }




    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7*sizeof(float), 0);

    GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
    glEnableVertexAttribArray(colAttrib);
    glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(2*sizeof(float)));


    GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
    glEnableVertexAttribArray(texAttrib);
    glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(5*sizeof(float)));



    return shaderProgram;
}

openGlRenderer.cpp

Init:


...
   glClearColor(0,1,0,1);
 string path ("textures/metalplate.png");
 texture = Texture2D::Load(path);

Draw:


...
glClear(GL_COLOR_BUFFER_BIT);
texture->Draw();

You didn’t call glBindTexture before you called glTexImage2D.

Thanks for your quick response.
I changed that, unfortunately still getting the same result :confused:

I’d recommend getting filling the quad with a solid color (without texture) working first. Then when you add texture support, if you have problems, you’ll know where the problem lies.

If I change

  gl_FragColor = texture2D(tex, Texcoord) * vec4(Color, 1.0);

to

  gl_FragColor = vec4(Color, 1.0);

it works, so I highly think it must be the texture.

Let’s say I’m loading it wrong, I also tested with this:

   float pixels[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_FLOAT, pixels);

Still gives me the same.

What I also found out is whenever I use

 glGenerateMipmap(GL_TEXTURE_2D);

glGetError returns 1281.

Okay, I got it to work. Pretty weird but well that was expected.

One post I found googling got me the idea to put these lines

 GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7*sizeof(float), 0);

    GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
    glEnableVertexAttribArray(colAttrib);
    glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(2*sizeof(float)));


    GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
    glEnableVertexAttribArray(texAttrib);
    glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(5*sizeof(float)));

behind the texture binding, even through done differently in my code samples.
Now it works.