Home > Mobile >  Opengl is not using the correct texture
Opengl is not using the correct texture

Time:06-26

I have recently started learning opengl on learnopengl.com. I am the chapter about textures. I have managed to load 2 textures however when I tell opengl to render the texture currently bound to GL_TEXTURE0 it instead draws the texture currently bound to GL_TEXTURE1.

My main.c file looks like this:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include "glad/glad.h"
#include "GLFW/glfw3.h"
#include "stb/stb_image_init.h"

#define WIDTH 1080
#define HEIGHT 720

typedef unsigned int uint;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void process_input(GLFWwindow* window);
void check_shader_compilation(GLuint shader_object, GLenum shader_type);
void check_shader_linking(GLuint shader_program);
char* get_shader_code(const char* path);

int main(void) {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Triangle", NULL, NULL);

    if (window == NULL) {
        printf("Unable to create glfw window!\n");
        return -1;
    }

    glfwMakeContextCurrent(window);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        printf("Couldn't initialize glad!\n");
        return -1;
    }

    glViewport(0, 0, WIDTH, HEIGHT);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    char* vertex_shader_code = get_shader_code("shaders/vertex.glsl");

    GLuint vertex_shader_object = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader_object, 1, &vertex_shader_code, NULL);
    glCompileShader(vertex_shader_object);
    check_shader_compilation(vertex_shader_object, GL_VERTEX_SHADER);

    free(vertex_shader_code);

    char* fragment_shader_code = get_shader_code("shaders/fragment.glsl");

    GLuint fragment_shader_object = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader_object, 1, &fragment_shader_code, NULL);
    glCompileShader(fragment_shader_object);

    check_shader_compilation(fragment_shader_object, GL_FRAGMENT_SHADER);
    free(fragment_shader_code);

    uint shader_program = glCreateProgram();
    glAttachShader(shader_program, vertex_shader_object);
    glAttachShader(shader_program, fragment_shader_object);
    glLinkProgram(shader_program);
    glUseProgram(shader_program);

    check_shader_linking(shader_program);

    float rectangle_data[] = {
        // Coords           Colors              Texture coords
       -0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   0.0f,  0.0f, // Bottom Left
        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,  1.0f, // Top Left
        0.5f,  0.5f, 0.0f,  1.0f, 1.0f, 0.0f,   1.0f,  1.0f, // Top Right
    };

    unsigned int indicies[] = {
        0, 2, 3,
        0, 1, 3,
    };

    uint vao, vbo, ebo;
    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);
    glGenBuffers(1, &ebo);

    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

    glBufferData(GL_ARRAY_BUFFER, sizeof(rectangle_data), rectangle_data, GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indicies), indicies, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float)*8, (void*)0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float)*8, (void*)(sizeof(float)*3));
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float)*8, (void*)(sizeof(float)*6));
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);

    float border_color[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    uint texture_buffer, texture2_buffer;
    glGenBuffers(1, &texture_buffer);
    glBindTexture(GL_TEXTURE_2D, texture_buffer);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    stbi_set_flip_vertically_on_load(true);
    int width = 0, height = 0, n_channels = 0;
    unsigned char* texture_image = stbi_load("assets/textures/luffy.jpg", &width, &height, &n_channels, 0);

    if (texture_image) {
        printf("Loaded texture0!\n");
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_image);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else {
        printf("Couldn't find the image for the texture\n");
        exit(-1);
    }

    stbi_image_free(texture_image);

    glGenBuffers(1, &texture2_buffer);
    glBindTexture(GL_TEXTURE_2D, texture2_buffer);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    int t2_width = 0, t2_height = 0, t2_n_channels = 0;
    unsigned char* texture2_image = stbi_load("assets/textures/face.png", &t2_width, &t2_height, &t2_n_channels, 0);

    if (texture2_image) {
        printf("Loaded texture1!\n");
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, t2_width, t2_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture2_image);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else {
        printf("Couldn't find the image for texture2\n");
        exit(-1);
    }

    stbi_image_free(texture2_image);

    glUseProgram(shader_program);
    glUniform1i(glGetUniformLocation(shader_program, "luffy"), 0);
    glUniform1i(glGetUniformLocation(shader_program, "face"),  1);

    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    while (!glfwWindowShouldClose(window)) {
        process_input(window);
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture_buffer);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2_buffer);

        glBindVertexArray(vao);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwPollEvents();
        glfwSwapBuffers(window);
    }

    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ebo);
    glDeleteShader(vertex_shader_object);
    glDeleteShader(fragment_shader_object);
    glDeleteProgram(shader_program);

    glfwTerminate();
    return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
    glViewport(0, 0, width, height);
}

void process_input(GLFWwindow* window) {
    if (glfwGetKey(window, GLFW_KEY_Q) == true) {
        glfwSetWindowShouldClose(window, true);
    }
}

void check_shader_compilation(GLuint shader_object, GLenum shader_type) {
    char* print_shader_type;
    switch (shader_type) {
        case GL_VERTEX_SHADER:
            print_shader_type = "vertex";
            break; 

        case GL_FRAGMENT_SHADER:
            print_shader_type = "fragment";
            break;
        
        default:
            printf("Cannot check for shader compilation, the shader_type is not GL_VERTEX_SHADER or GL_FRAGMENT_SHADER!\n");
            exit(-1);
    }

    int shader_status;
    glGetShaderiv(shader_object, GL_COMPILE_STATUS, &shader_status);

    if (!shader_status) {
        int message_length;
        GLchar error[1024];
        glGetShaderInfoLog(shader_object, 1024, &message_length, error);
        printf("Could not compile the %s shader: \n %s\n", print_shader_type,  error);
        exit(-1);
    }
    else {
        printf("Compiled the %s shader!\n", print_shader_type);
    }
}

void check_shader_linking(GLuint shader_program) {
    int linking_status;
    glGetProgramiv(shader_program, GL_LINK_STATUS, &linking_status);

    if (!linking_status) {
        int message_length;
        GLchar error[1024];
        glGetProgramInfoLog(shader_program, 1024, &message_length, error);
        printf("Could not link the shader program:\n %s\n", error);
        exit(-1);
    }
    else {
        printf("Linked the shader program!\n");
    }
}

char* get_shader_code(const char* path) {
    FILE* shader_file = fopen(path, "rb");

    if (!shader_file) {
        printf("Incorrect file path for shader: %s\n", path);
        exit(-1);
    }

    fseek(shader_file, 0, SEEK_END);
    int file_size = ftell(shader_file);
    rewind(shader_file);
    char* shader_code = malloc(file_size   1);
    shader_code[file_size] = '\0';
    fread(shader_code, sizeof(char), file_size, shader_file);
    return shader_code;
}

My Vertex shader is:

#version 330

layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 colors;
layout (location = 2) in vec2 texCoords;

out vec3 vertex_colors;
out vec2 tex_coords;

void main() {
    gl_Position = vec4(pos.x, pos.y, pos.z, 1.0);
    vertex_colors = colors;
    tex_coords = texCoords;
}

And my fragment shader is:

#version 330 core

out vec4 fragColor;

in vec3 vertex_colors;
in vec2 tex_coords;

uniform sampler2D luffy;
uniform sampler2D face;

void main() {
    fragColor = texture(luffy, tex_coords);
}

Whenever I run the program, it texture it uses is the image in face.png, whereas I told it to use the image in luffy.jpg.

CodePudding user response:

You never create any texture objects:

glGenBuffers(1, &texture_buffer);
glBindTexture(GL_TEXTURE_2D, texture_buffer);

glGenBuffers is for buffer objects, not for texture objects. You have to use glGenTextures. (Also calling your variable texture_buffer here is very confusing. There are buffer textures in the GL, but you're not using those here).

And since you use a core profile, the glBindTexture() call will just generate a GL error and have no other effect, becuase the object name you try to bind never was generated by glGenTextures. So in effect, you are working with texture object 0 here, and load both images to that texture object, with the latter overwriting the former. In a core profiler, using texture object 0 actually shouldn't work, but many drivers still allow it (as it was allowed in legacy GL), so that you actually see any texture at all is not guaranteed either.

  • Related