OpenGL Texture won't draw

527 views Asked by At

I followed an opengl tutorial and created a more object oriented version. I want to draw a Texture but the only thing which works is the glClearColor command. I have no idea why it doesn't work. I tried everything. Here's the code:

Sprite.cpp

#include "Sprite.h"
#include <SOIL\SOIL.h>



Sprite::Sprite(const char* texturePath, float x, float y, GLuint width, GLuint height)
{
    Sprite::init(texturePath, x, y, width, height);
}


Sprite::~Sprite()
{
}

void Sprite::init(const char* texturePath, float x, float y, GLuint width, GLuint height)
{
    Logger::info("Initializing Sprite...");
    _x = x;
    _y = y;
    _width = width;
    _height = height;

    // Build and compile our shader program



    // Set up vertex data (and buffer(s)) and attribute pointers
    const GLfloat vertices[] = {
        // Positions                        // Colors           // Texture Coords
        _x,        _y,         0.0f,        0.0f, 0.0f, 0.0f,   1.0f, 1.0f,
        _x,        _y + _height, 0.0f,        0.0f, 0.0f, 0.0f,   1.0f, 0.0f,
        _x + _width, _y,         0.0f,        0.0f, 0.0f, 0.0f,   0.0f, 0.0f,
        _y + _width, _y + _height, 0.0f,        0.0f, 0.0f, 0.0f,   0.0f, 1.0f
    };



    /*GLfloat vertices[] = {
        // Positions          // Colors           // Texture Coords
        0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // Top Right
        0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // Bottom Right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // Bottom Left
        -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f    // Top Left 
    };

    */





    constexpr GLuint indices[] = {  // Note that we start from 0!
        0, 1, 3, // First Triangle
        1, 2, 3  // Second Triangle
    };


    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // Position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // Color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // TexCoord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    glBindVertexArray(0); // Unbind VAO


                          // Load and create a texture 
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture); // All upcoming GL_TEXTURE_2D operations now have effect on this texture object
                                           // Set the texture wrapping parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);   // Set texture wrapping to GL_REPEAT (usually basic wrapping method)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // Set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


    // Load image, create texture and generate mipmaps
    int twidth, theight;
    unsigned char* image = SOIL_load_image(texturePath, &twidth, &theight, 0, SOIL_LOAD_RGB);
    if (image == 0)
    {
        Logger::fatalError("Image is null!");
    }

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
    glGenerateMipmap(GL_TEXTURE_2D);
    SOIL_free_image_data(image);
    glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture.






    //_texture2 = texture2;
    Logger::info("Sprite initialization succesful!");

}

void Sprite::draw(Shader *shader)
{
/*  glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, _texture1);
    glUniform1i(glGetUniformLocation(shader->_programID, "ourTexture1"), 0);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, _texture2);
    glUniform1i(glGetUniformLocation(shader->_programID, "ourTexture2"), 1);
    */









    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);


    // Bind Texture
    glBindTexture(GL_TEXTURE_2D, texture);

    if (texture == 0) {
        Logger::fatalError("texture1 is null");
    }

    if (shader == 0) {
        Logger::fatalError("shader is null");
    }


    if (VAO == 0) {
        Logger::fatalError("VAO is null");
    }

    // Activate shader
//  glActiveTexture(GL_TEXTURE0);
//  glBindTexture(GL_TEXTURE_2D, texture);
    //glUniform1i(glGetUniformLocation(shader->_programID, "ourTexture"), 0);
    //shader->Use();

    // Draw container
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

}

Shader.cpp

#include "Shader.h"



Shader::Shader(const GLchar* vertexShaderPath, const GLchar* fragmentShaderPath)
{
    std::string vertexCode;
    std::string fragmentCode;
    std::ifstream vertexShaderFile;
    std::ifstream fragmentShaderFile;
    // ensures ifstream objects can throw exceptions:
    vertexShaderFile.exceptions(std::ifstream::badbit);
    fragmentShaderFile.exceptions(std::ifstream::badbit);
    try
    {
        // Open files
        vertexShaderFile.open(vertexShaderPath);
        fragmentShaderFile.open(fragmentShaderPath);
        std::stringstream vShaderStream, fShaderStream;
        // Read file's buffer contents into streams
        vShaderStream << vertexShaderFile.rdbuf();
        fShaderStream << fragmentShaderFile.rdbuf();
        // close file handlers
        vertexShaderFile.close();
        fragmentShaderFile.close();
        // Convert stream into GLchar array
        vertexCode = vShaderStream.str();
        fragmentCode = fShaderStream.str();
    }
    catch (std::ifstream::failure e)
    {
        Logger::info("ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ");
    }
    const GLchar* vertexShaderCode = vertexCode.c_str();
    const GLchar* fragmentShaderCode = fragmentCode.c_str();

    Shader::compileShaders(vertexShaderCode, fragmentShaderCode);

}


void Shader::compileShaders(const GLchar* vertexShaderCode, const GLchar* fragmentShaderCode) {
    Logger::info("Compiling Shaders...");
    GLuint vertex, fragment;
    GLint success;
    GLchar infoLog[512];

    // Vertex Shader
    vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vertexShaderCode, NULL);
    glCompileShader(vertex);
    // Print compile errors if any
    glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertex, 512, NULL, infoLog);
        Logger::fatalError("ERROR::SHADER::VERTEX::COMPILATION_FAILED");
    };

    // Similiar for Fragment Shader
    fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fragmentShaderCode, NULL);
    glCompileShader(fragment);
    // Print compile errors if any
    glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragment, 512, NULL, infoLog);
        Logger::fatalError("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED");
    };



    // Shader Program
    this->_programID = glCreateProgram();
    glAttachShader(this->_programID, vertex);
    glAttachShader(this->_programID, fragment);
    glLinkProgram(this->_programID);
    // Print linking errors if any
    glGetProgramiv(this->_programID, GL_LINK_STATUS, &success);
    if (!success)
    {
        glGetProgramInfoLog(this->_programID, 512, NULL, infoLog);
        Logger::fatalError("ERROR::SHADER::PROGRAM::LINKING_FAILED");
    }

    // Delete the shaders as they're linked into our program now and no longer necessery
    glDeleteShader(vertex);
    glDeleteShader(fragment);
    Logger::info("Shader compilation succesful!");
}

void Shader::Use() {
    glUseProgram(this->_programID);
}


Shader::~Shader()
{
}

MainGame.cpp

#include "MainGame.h"





MainGame::MainGame()
{
    _window = nullptr;
    _screenWidth = 1024;
    _screenHeight = 768;
    _gameState = GameState::PLAY;
}


MainGame::~MainGame()
{
}


void MainGame::run() {
    initSystems();
    gameLoop();
}

void MainGame::initSystems() {
    //Initialize SDL
    SDL_Init(SDL_INIT_EVERYTHING);
    //Create Window
    _window = SDL_CreateWindow("Half Life 3", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _screenWidth, _screenHeight, SDL_WINDOW_OPENGL);
    //glViewport(0, 0, _screenWidth, _screenHeight);
    if (_window == nullptr) {
        Logger::fatalError("SDL Window could not be created!");
    }
    SDL_GLContext glContext = SDL_GL_CreateContext(_window);
    if (glContext == nullptr) {
        Logger::fatalError("SDL_GL context could not be created");
    }

    GLenum error = glewInit();
    if (error != GLEW_OK) {
        Logger::fatalError("Could not initialize glew!");
    }

    Logger::info("Initialization succesful");

    //Double Buffer: Smooth, no flickering
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    glClearColor(0, 0, 1, 1.0);

    Shader shader("Shaders/Shader.vert", "Shaders/Shader.frag");
    _shader = &shader;
    Sprite sprite("Textures/wall.jpg", 0.5f, 0.5f, 100, 100);
    _texture = &sprite;

}

void MainGame::gameLoop() {
    while (_gameState != GameState::EXIT) {
        processInput();
        drawGame();
    }
}
void MainGame::processInput() {
    SDL_Event evnt;
    while (SDL_PollEvent(&evnt) == true) {
        switch (evnt.type) {
        case SDL_QUIT:
            _gameState = GameState::EXIT;
        //  std::cout << "Quit Event" << std::endl;
            break;
        case SDL_MOUSEMOTION:
        //  std::cout << "x: " << evnt.motion.x << " y: " << evnt.motion.y << std::endl;
            break;
        }
    }
}
void MainGame::drawGame() {
//  glClearDepth(1.0);
//  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    //_shader->Use();

    // Bind Textures using texture units
    _texture->draw(_shader);



    // Swap the screen buffers
    SDL_GL_SwapWindow(_window);

}

Fragment shader:

#version 330 core
in vec3 ourColor;
in vec2 TexCoord;

out vec4 color;

uniform sampler2D ourTexture;

void main()
{
    color = texture(ourTexture, TexCoord);
}

Vertex shader:

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;

out vec3 ourColor;
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(position, 1.0f);
    ourColor = color;
    TexCoord = texCoord;
}

Console log:

Initialization succesful
Compiling Shaders...
Shader compilation succesful!
Initializing Sprite...
Sprite initialization succesful!

You see, everything loads correctly and initializes correctly and there are no errors. It still displays nothing but the glClearColor. What's wrong?

1

There are 1 answers

0
Malcolm McLean On

The blank screen effect is very common with Open GL graphics. It means the view, camera, lighting, or something has been set up in such a way that you see nothing.

The cure is to comment out all your code, except the clear which works (that's an important first step, you are at least getting Open GL output). Then add code until you see something, anything, on screen.

You then gradually shift the anything ) to what you want to see by commenting the code back in, and commenting it out again if you go back to the blank screen effect.