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.