diff --git a/shaders/frag.glsl b/shaders/frag.glsl index 2772905..12261d8 100644 --- a/shaders/frag.glsl +++ b/shaders/frag.glsl @@ -1,9 +1,14 @@ #version 330 core in vec3 vert_color; +in vec2 tex_coords; out vec4 color; +uniform float mix_factor; +uniform sampler2D texture0; +uniform sampler2D texture1; + void main() { - color = vec4(vert_color, 1.0f); + color = mix(texture(texture0, tex_coords), texture(texture1, tex_coords), mix_factor); }; diff --git a/shaders/vert.glsl b/shaders/vert.glsl index 082b94d..2664d62 100644 --- a/shaders/vert.glsl +++ b/shaders/vert.glsl @@ -2,10 +2,13 @@ layout(location=0) in vec3 position; layout(location=1) in vec3 color; +layout(location=2) in vec2 uv; out vec3 vert_color; +out vec2 tex_coords; void main() { - vert_color = color; + tex_coords = uv; + vert_color = color; gl_Position = vec4(position, 1.0); }; diff --git a/src/main.cc b/src/main.cc index f3416db..a58776f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -10,6 +10,10 @@ #include "glm/gtx/rotate_vector.hpp" #include "glm/gtx/string_cast.hpp" +// STB Image +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + // SDL #include #include @@ -44,8 +48,8 @@ class Shader { Shader(const std::string &vert_file, const std::string &frag_file); ~Shader(); void activate(); - private: GLuint program; + private: void link_program(GLuint vert, GLuint frag); GLuint load_and_compile_shader(const std::string &filepath, GLenum shader_type); std::string load_shader_from_file(const std::string &filepath); @@ -78,18 +82,30 @@ int main() { return EXIT_CODE_GLAD_LOADER_FAILED; } + // Set texture options + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); std::vector vertices = { -0.5f, -0.5f, 0.0f, // position 1.0f, 0.0f, 0.0f, // colour + 0.0f, 0.0f, // uv 0.5f, -0.5f, 0.0f, // position 0.0f, 0.0f, 1.0f, // colour - 0.0f, 0.5f, 0.0f, // position + 1.0f, 0.0f, // uv + -0.5f, 0.5f, 0.0f, // position 0.0f, 1.0f, 0.0f, // colour + 0.0f, 1.0f, // uv + 0.5f, 0.5f, 0.0f, // position + 0.5f, 0.5f, 0.5f, // colour + 1.0f, 1.0f, // uv }; - std::vector indices = {0, 1, 2}; + std::vector indices = {0, 1, 2, 2, 1, 3}; GLuint vao = 0; glGenVertexArrays(1, &vao); @@ -105,10 +121,12 @@ int main() { glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.data(), GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void *)0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *)0); glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void *)(3 * sizeof(GLfloat))); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *)(6 * sizeof(GLfloat))); + glEnableVertexAttribArray(2); glBindVertexArray(0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -116,7 +134,46 @@ int main() { glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); + stbi_set_flip_vertically_on_load(true); + + // Load texture + int32_t width[2], height[2], channels[2]; + uint8_t *container = stbi_load("images/container.jpg", &width[0], &height[0], &channels[0], 0); + uint8_t *awesomeface = stbi_load("images/awesomeface.png", &width[1], &height[1], &channels[1], 0); + + GLuint textures[2]; + glGenTextures(2, textures); + + glActiveTexture(GL_TEXTURE0); // activate the texture unit first before binding texture + glBindTexture(GL_TEXTURE_2D, textures[0]); + if (container) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width[0], height[0], 0, GL_RGB, GL_UNSIGNED_BYTE, container); + glGenerateMipmap(GL_TEXTURE_2D); + + stbi_image_free(container); + } else { + printf("Failed to load container texture \n"); + } + + glActiveTexture(GL_TEXTURE1); // activate the texture unit first before binding texture + glBindTexture(GL_TEXTURE_2D, textures[1]); + if (container) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width[1], height[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, awesomeface); + glGenerateMipmap(GL_TEXTURE_2D); + + stbi_image_free(awesomeface); + } else { + printf("Failed to load container texture \n"); + } + + glBindTexture(GL_TEXTURE_2D, 0); + Shader main_shader {"shaders/vert.glsl", "shaders/frag.glsl"}; + main_shader.activate(); + glUniform1i(glGetUniformLocation(main_shader.program, "texture0"), 0); + glUniform1i(glGetUniformLocation(main_shader.program, "texture1"), 1); + + float texture_mix_factor = 0.2f; bool running = true; SDL_Event event = {}; @@ -129,6 +186,10 @@ int main() { case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) { running = false; + } else if (event.key.keysym.sym == SDLK_UP) { + texture_mix_factor += 0.1f; + } else if (event.key.keysym.sym == SDLK_DOWN) { + texture_mix_factor -= 0.1f; } break; case SDL_WINDOWEVENT: @@ -145,12 +206,21 @@ int main() { } } + texture_mix_factor = texture_mix_factor < 0.0f ? + 0.0f : texture_mix_factor > 1.0f ? + 1.0f : texture_mix_factor; + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); main_shader.activate(); + glUniform1f(glGetUniformLocation(main_shader.program, "mix_factor"), texture_mix_factor); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textures[0]); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, textures[1]); glBindVertexArray(vao); - glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, NULL); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL); SDL_GL_SwapWindow(window); }