Search code examples
c++opengltexturesglfw

OpenGL texture does not work with no errors - black screen


I just don't understand why it does not work - it just shows a white screen... (or a black one, because glClearColor) PS. > the texture also broke everything else... I checked the shaders and the code: no errors, no responses, nothing. Including the texture. I think the shaders are right, but i don't know about anything else. I also have all the libraries: GLEW, GLFW, OPENGL, a single header file copied from stb_image...

Here is the code:

#include <iostream>
#include <fstream>
#include <string>
#include "GL/glew.h"
#include "GLFW/glfw3.h"

#define ASSERT(x) if(!(x)) __debugbreak();
#define CALL(x) OpenGlClError(); x; ASSERT(OpenGlError(#x, __LINE__, __FILE__));

#define STB_IMAGE_IMPLEMENTATION
#include "extern/stb_image/stb_image_vendor/stb_image.h"

void OpenGlClError() {
    while (glGetError());
}
bool OpenGlError(const char* func, int line, const char* file) {
    while (GLenum error = glGetError()) {
        std::cout << "GLTest: OPENGL ERROR: " << error << " in function " << func << " at line " << line << ", FILE: " << file << "\n";
        return false;
    }
    return true;
}

#define ASSERT(x) if(!(x)) __debugbreak();
#define CALL(x) OpenGlClError(); x; ASSERT(OpenGlError(#x, __LINE__, __FILE__));

class Texture {
private:
    unsigned int TextID;
    std::string FilePath;
    unsigned char* LocalBuffer;
    int Width, Height, BytesPixel;
public:
    Texture(const std::string path)
        : TextID(0), FilePath(path), LocalBuffer(nullptr), Width(0), Height(0), BytesPixel(0) {
        CALL(glGenTextures(1, &TextID));
        CALL(glBindTexture(GL_TEXTURE_2D, TextID));

        stbi_set_flip_vertically_on_load(1);
        LocalBuffer = stbi_load(path.c_str(), &Width, &Height, &BytesPixel, 4);

        CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
        CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
        CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
        CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));

        CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, LocalBuffer));
        CALL(glBindTexture(GL_TEXTURE_2D, 0));

        if (LocalBuffer) { //if localbuffer exists
            stbi_image_free(LocalBuffer);
        }
    }
    ~Texture() {
        glDeleteTextures(1, &TextID);
    }
    void Bind(unsigned int slot = 0){
        CALL(glActiveTexture(GL_TEXTURE0 + slot));
        CALL(glBindTexture(GL_TEXTURE_2D, TextID));
    }
    void Unbind() {
        glBindTexture(GL_TEXTURE_2D, 0);
    }
};

static std::string ReadShader(const std::string& filename) {
    std::ifstream stream;
    std::string line;
    std::string str;
    stream.open(filename);
    while (getline(stream, line)) {
        str.append(line).append("\n");
    }
    std::cout << str;
    stream.close();
    return str;
}
static unsigned int CompileShader(const std::string& source, unsigned int type) {
    unsigned int shader = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(shader, 1, &src, nullptr);
    glCompileShader(shader);
    int result;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
    // i - int
    // v - vector
    if (result == GL_FALSE) {
        std::cout << "Shader cannot be compiled.\n" << (type == GL_VERTEX_SHADER ? "vertex s." : "fragments.") << "\n";
        int length;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
        char* message = (char*)_malloca(length * sizeof(char));
        glGetShaderInfoLog(shader, length, &length, message);
        std::cout << message << "\n";
        glDeleteShader(shader);
    }
    return shader;
}
static int CreateShader(const std::string& vShader, const std::string& fShader) {
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(vShader, GL_VERTEX_SHADER);
    unsigned int fs = CompileShader(fShader, GL_FRAGMENT_SHADER);
    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);
    glDeleteShader(vs);
    glDeleteShader(fs);
    return program;
}

int main() {
    glfwInit();
    //make window
    GLFWwindow* window;
    //std::cout << "GLTest:" << glGetString(GL_VERSION) << "\n";
    window = glfwCreateWindow(800, 500, "Modern OpenGL Test", NULL, NULL);
    glfwMakeContextCurrent(window);
    glewInit();

    float texver[16] = {
         -1.0f, -1.0f , 0.0f, 0.0f,
         1.0f, -1.0f, 1.0f, 0.0f,
         1.0f, 1.0f, 1.0f, 1.0f,
         -1.0f, -1.0f, 0.0f, 1.0f
    };

    float texindex[6] = {
        0, 1, 2,
        2, 3, 0
    };

    float vertices[12] = {
         1.0f, 1.0f,
         0.0f, -1.0f,
         1.0f, -1.0f,

         -1.0f, 1.0f,
          0.0f, 1.0f,
         -1.0f, -1.0f
    };

    //unsigned int varray; //< dont actually need it...
    //glGenVertexArrays(1, &varray);
    //glBindVertexArray(varray);

    //unsigned int vb;
    //glGenBuffers(1, &vb);
    //glBindBuffer(GL_ARRAY_BUFFER, vb);
    //glBufferData(GL_ARRAY_BUFFER, 6 * 2 * sizeof(float), vertices, GL_STATIC_DRAW);
    //
    //glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0); //said hey we have this set up like that, links in vertex array
    //glEnableVertexAttribArray(0); //yea remember it

    unsigned int tb;
    glGenBuffers(1, &tb);
    glBindBuffer(GL_ARRAY_BUFFER, tb);
    glBufferData(GL_ARRAY_BUFFER, 4 * 4 * sizeof(float), texver, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); //said hey we have this set up like that, links in vertex array
    glEnableVertexAttribArray(0); //yea remember it

    unsigned int shaders = CreateShader(ReadShader("shaders/basic_texture_vertex.shader"), ReadShader("shaders/basic_texture_fragment.shader"));
    glUseProgram(shaders);
    
    Texture tt("../!Assets/editor/img/intro_logo.png");
    tt.Bind();

    CALL(int location = glGetUniformLocation(shaders, "u_Texture"));
    CALL(glUniform1i(location, 0));

    CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));

    while (!glfwWindowShouldClose(window)) {
        glClear(GL_COLOR_BUFFER_BIT);
        glClearColor(1, 1, 1, 1);
        //Drawing
        glDrawArrays(GL_TRIANGLES, 0, 6 * 2);


        glfwSwapBuffers(window);
        glfwPollEvents();

    }
    glDeleteProgram(shaders);
    glfwTerminate();
}

Solution

  • You missed to specify the vertex attribute for the texture coordinates. For instance

    unsigned int tb;
    glGenBuffers(1, &tb);
    glBindBuffer(GL_ARRAY_BUFFER, tb);
    glBufferData(GL_ARRAY_BUFFER, 4 * 4 * sizeof(float), texver, GL_STATIC_DRAW);
    
    // vertex cooridnates
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
    glEnableVertexAttribArray(0);
    
    // texture coordinates
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float)*4, (void*)(sizeof(float)*2));
    glEnableVertexAttribArray(1);
    

    The last argument of glDrawArrays is the number of vertices. Since you just have 4 vertices, the argument cannot be 6*2.
    Anyway, since you have specified an array indices it seems that you want to specify an Index buffer. You have to use glDrawElements for indexed rendering.

    The indices have to be an integral data type:

    int texindex[6] = {
        0, 1, 2,
        0, 2, 3
    };
    

    Generate the index (GL_ELEMENT_ARRAY_BUFFER) buffer:

    unsigned int ibo;
    glGenBuffers(1, &ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(int), texindex, GL_STATIC_DRAW); 
    

    Draw the tringles:

    glDrawArrays(GL_TRIANGLES, 0, 6 * 2);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);