LearnOpenGL - Textures | Not seeing awesomeface.png

Viewed 39

So even though I tried to load awesomeface.png the same way I did with wall.jpg, it is not visible (as you can see from the image). Honestly I think I did something wrong in the part where I activate the texture2 uniform, but I don't know how to fix it so if you could kindly help me understand how to fix it or how to debug the code I would be very grateful.

main.rs

extern crate gl;
extern crate glfw;
extern crate image;

pub mod shaders;

use gl::types::*;
use glfw::Context;
use shaders::Shader;

fn main() {
    // Setting up glfw
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap(); // Initialize Glfw library
    glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3)); // Using OGL version 330
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(
        glfw::OpenGlProfileHint::Core, // Using core profile
    ));
    glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));

    // Setting up the window and the events receiver
    let (mut window, events) = glfw
        .create_window(1080, 720, "Hello Triangle", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window");

    window.make_current();
    window.set_key_polling(true); // Handle keyboard input
    window.set_framebuffer_size_polling(true); // Handle window resize
    window.set_resizable(true);

    // Setting up gl
    gl::load_with(|s| glfw.get_proc_address_raw(s));

    // Setting up Shader and Program
    let shader = Shader::new("shaders/triangle.vert", "shaders/triangle.frag").unwrap();
    //shader.set_float_uniform("green", 0.1);
    shader.set_int_uniform("texture1", 0);
    shader.set_int_uniform("texture2", 1);
    shader.set_used();

    // Rectangle
    let vertices: [GLfloat; 24] = [
        // positions    // colors      // texture
        0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // bottom right
        -0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, // bottom left
        0.0, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 1.0, // top
    ];

    let indices: [u32; 3] = [
        0, 1, 2, // first triangle
    ];

    let mut vao = 0;
    let mut vbo = 0;
    let mut ebo = 0;

    let mut texture1 = 0;
    let mut texture2 = 0;

    unsafe {
        gl::GenVertexArrays(1, &mut vao); // Generate VAO
        gl::GenBuffers(1, &mut vbo); // Generate VBO
        gl::GenBuffers(1, &mut ebo); // Generate EBO

        gl::BindVertexArray(vao); // Bind VAO

        gl::BindBuffer(gl::ARRAY_BUFFER, vbo); // Bind VBO
        gl::BufferData(
            gl::ARRAY_BUFFER,
            (vertices.len() * std::mem::size_of::<GLfloat>()) as GLsizeiptr,
            vertices.as_ptr() as *const GLvoid,
            gl::DYNAMIC_DRAW,
        );

        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo); // Bind EBO
        gl::BufferData(
            gl::ELEMENT_ARRAY_BUFFER,
            (indices.len() * std::mem::size_of::<GLuint>()) as GLsizeiptr,
            indices.as_ptr() as *const GLvoid,
            gl::STATIC_DRAW,
        );

        gl::EnableVertexAttribArray(0); // Enable "Position" in triangle.vert (the index is 0 because the "location" = 0)
        gl::VertexAttribPointer(
            0,
            3,
            gl::FLOAT,
            gl::FALSE,
            (8 * std::mem::size_of::<f32>()) as GLint,
            std::ptr::null(),
        );
        gl::EnableVertexAttribArray(1); // Enable "Color" in triangle.vert (the index is 0 because the "location" = 1)
        gl::VertexAttribPointer(
            1,
            3,
            gl::FLOAT,
            gl::FALSE,
            (8 * std::mem::size_of::<f32>()) as GLint,
            (3 * std::mem::size_of::<f32>()) as *const GLvoid,
        );

        gl::EnableVertexAttribArray(2);
        gl::VertexAttribPointer(
            2,
            2,
            gl::FLOAT,
            gl::FALSE,
            (8 * std::mem::size_of::<f32>()) as GLint,
            (6 * std::mem::size_of::<f32>()) as *const GLvoid,
        );

        /* let border_color = [1.0, 1.0, 0.0, 1.0];
        gl::TextureParameterfv(
            gl::TEXTURE_2D,
            gl::TEXTURE_BORDER_COLOR,
            border_color.as_ptr(),
        ); */

        gl::TextureParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_MIN_FILTER,
            gl::LINEAR_MIPMAP_LINEAR as i32,
        );
        gl::TextureParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);

        let texture_image_1 = image::io::Reader::open("texture/wall.jpg")
            .unwrap()
            .decode()
            .unwrap();

        let texture_image_2 = image::io::Reader::open("texture/awesomeface.png")
            .unwrap()
            .decode()
            .unwrap();

        gl::GenTextures(1, &mut texture1);
        gl::BindTexture(gl::TEXTURE_2D, texture1);
        gl::TextureParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_WRAP_S,
            gl::MIRRORED_REPEAT as i32,
        );
        gl::TextureParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_WRAP_T,
            gl::MIRRORED_REPEAT as i32,
        );
        gl::TextureParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
        gl::TextureParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        gl::TexImage2D(
            gl::TEXTURE_2D,
            0,
            gl::RGB as GLint,
            texture_image_1.width() as GLint,
            texture_image_1.height() as GLint,
            0,
            gl::RGB,
            gl::UNSIGNED_BYTE,
            texture_image_1.as_bytes().as_ptr() as *const GLvoid,
        );
        gl::GenerateMipmap(gl::TEXTURE_2D);

        gl::GenTextures(1, &mut texture2);
        gl::BindTexture(gl::TEXTURE_2D, texture2);
        gl::TextureParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_WRAP_S,
            gl::MIRRORED_REPEAT as i32,
        );
        gl::TextureParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_WRAP_T,
            gl::MIRRORED_REPEAT as i32,
        );
        gl::TextureParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
        gl::TextureParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        gl::TexImage2D(
            gl::TEXTURE_2D,
            0,
            gl::RGB as GLint,
            texture_image_2.width() as GLint,
            texture_image_2.height() as GLint,
            0,
            gl::RGBA,
            gl::UNSIGNED_BYTE,
            texture_image_2.as_bytes().as_ptr() as *const GLvoid,
        );
        gl::GenerateMipmap(gl::TEXTURE_2D);
    }

    // Main Loop
    while !window.should_close() {
        // Input handling
        process_input(&mut glfw, &mut window, &events);

        // Rendering
        unsafe {
            gl::ClearColor(0.0, 0.0, 0.0, 0.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            gl::ActiveTexture(gl::TEXTURE0);
            gl::BindTexture(gl::TEXTURE_2D, texture1);
            gl::ActiveTexture(gl::TEXTURE1);
            gl::BindTexture(gl::TEXTURE_2D, texture2);

            gl::BindVertexArray(vao); // Bind vao
            gl::DrawElements(gl::TRIANGLES, 3, gl::UNSIGNED_INT, std::ptr::null()); // Rendering the triangle
            gl::BindVertexArray(0); // Unbind vao
        }

        // Swap front and back buffer
        window.swap_buffers();
    }
}

#[allow(clippy::single_match)]
fn process_input(
    glfw: &mut glfw::Glfw,
    window: &mut glfw::Window,
    events: &std::sync::mpsc::Receiver<(f64, glfw::WindowEvent)>,
) {
    // Poll events
    glfw.poll_events();
    for (_, event) in glfw::flush_messages(events) {
        match event {
            glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _) => {
                window.set_should_close(true);
            }

            glfw::WindowEvent::Key(glfw::Key::W, _, glfw::Action::Press, _) => unsafe {
                gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);
            },

            glfw::WindowEvent::Key(glfw::Key::F, _, glfw::Action::Press, _) => unsafe {
                gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL);
            },
            _ => {}
        }
    }
}

shaders.rs

use std::{fs::File, io::Read, path::Path};

use gl::types::*;

pub struct Shader {
    id: GLuint,
}

impl Shader {
    // Constructor
    pub fn new(vertex_shader_path: &str, fragment_shader_path: &str) -> Result<Shader, String> {
        // 1. Retrieve the vertex/fragment source code
        let vertex_shader_code = code_from_path(Path::new(vertex_shader_path));
        let fragment_shader_code = code_from_path(Path::new(fragment_shader_path));
        // 2. Compile shader
        let vertex_shader = shader_from_source(&vertex_shader_code, gl::VERTEX_SHADER).unwrap();
        let fragment_shader =
            shader_from_source(&fragment_shader_code, gl::FRAGMENT_SHADER).unwrap();
        // 3. Shader Program
        let id = create_program([vertex_shader, fragment_shader])?;
        Ok(Shader { id })
    }

    // Get the id
    pub fn id(&self) -> GLuint {
        self.id
    }

    // Use\activate the shader
    pub fn set_used(&self) {
        unsafe { gl::UseProgram(self.id) }
    }

    // Utility uniform functions
    pub fn set_bool_uniform(&self, name: &str, value: bool) {
        unsafe {
            gl::Uniform1i(
                gl::GetUniformLocation(self.id, name.as_ptr() as *const i8),
                value as i32,
            )
        }
    }

    pub fn set_int_uniform(&self, name: &str, value: i32) {
        unsafe {
            gl::Uniform1i(
                gl::GetUniformLocation(self.id, name.as_ptr() as *const i8),
                value,
            )
        }
    }

    pub fn set_float_uniform(&self, name: &str, value: f32) {
        unsafe {
            gl::Uniform1f(
                gl::GetUniformLocation(self.id, name.as_ptr() as *const i8),
                value,
            )
        }
    }
}

impl Drop for Shader {
    fn drop(&mut self) {
        unsafe { gl::DeleteProgram(self.id) }
    }
}

/// Return CString of specified shader
fn code_from_path(path: &Path) -> std::ffi::CString {
    let mut shader_file = File::open(path).unwrap();
    let mut shader_code = String::new();

    shader_file.read_to_string(&mut shader_code).unwrap();

    std::ffi::CString::new(shader_code).unwrap()
}

/// Return CString of specified length
fn create_whitespace_cstring_with_len(len: usize) -> std::ffi::CString {
    // allocate buffer of correct size
    let mut buffer: Vec<u8> = Vec::with_capacity(len + 1);
    // fill it with len spaces
    buffer.extend([b' '].iter().cycle().take(len));
    // convert buffer to CString
    unsafe { std::ffi::CString::from_vec_unchecked(buffer) }
}

/// Base function to generate shader from source
fn shader_from_source(source: &std::ffi::CStr, kind: GLenum) -> Result<GLuint, String> {
    let id = unsafe { gl::CreateShader(kind) }; // Create shader
    let mut success: GLint = 1;

    unsafe {
        gl::ShaderSource(id, 1, &source.as_ptr(), std::ptr::null()); // Generate shader with shader source code
        gl::CompileShader(id); // Compile shader

        gl::GetShaderiv(id, gl::COMPILE_STATUS, &mut success); // Check for successful compilation
    }

    // Error handling
    if success == 0 {
        let mut len = 0;
        unsafe {
            gl::GetShaderiv(id, gl::INFO_LOG_LENGTH, &mut len); // Get length of error

            let error = create_whitespace_cstring_with_len(len as usize);

            gl::GetShaderInfoLog(id, len, std::ptr::null_mut(), error.as_ptr() as *mut GLchar); // Get the info of the error

            return Err(error.to_string_lossy().into_owned()); // Return the error
        }
    }

    Ok(id) // Return the shader
}

/// Create the program given the vertex and fragment shaders
fn create_program(shaders: [u32; 2]) -> Result<GLuint, String> {
    let id: GLuint = unsafe { gl::CreateProgram() };
    let mut success: GLint = 1;

    unsafe {
        gl::AttachShader(id, shaders[0]); // Vertex
        gl::AttachShader(id, shaders[1]); // Fragment
        gl::LinkProgram(id);

        gl::GetProgramiv(id, gl::LINK_STATUS, &mut success);

        gl::DeleteShader(shaders[0]);
        gl::DeleteShader(shaders[1]);
    }

    if success == 0 {
        let mut len = 0;
        unsafe {
            gl::GetShaderiv(id, gl::INFO_LOG_LENGTH, &mut len); // Get length of error

            let error = create_whitespace_cstring_with_len(len as usize);

            gl::GetShaderInfoLog(id, len, std::ptr::null_mut(), error.as_ptr() as *mut GLchar); // Get the info of the error

            return Err(error.to_string_lossy().into_owned()); // Return the error
        }
    }

    Ok(id)
}

triangle.frag

#version 330 core

out vec4 FragColor;  

in vec3 ourColor;
in vec2 TexCoord;

uniform sampler2D texture1;
uniform sampler2D texture2;
//uniform float green;

void main()
{
    FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}

triangle.vert

#version 330 core

layout (location = 0) in vec3 aPos;   // the position variable has attribute position 0
layout (location = 1) in vec3 aColor; // the color variable has attribute position 1
layout (location = 2) in vec2 aTexCoord;

out vec3 ourColor; // output a color to the fragment shader
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    ourColor = aColor; // set ourColor to the input color we got from the vertex data
    TexCoord = aTexCoord;
} 

This is what I see

Edit: I edited main.rs changing the order of the function calls as Rabbid76 suggested but it still doesn't work

1 Answers

gl::Uniform sets the value of a uniform variable in the default uniform block of the currently installed program. Therefore, you must install the program with gl::UseProgram before you can set the value of the uniform:

shader.set_used();
shader.set_int_uniform("texture1", 0);
shader.set_int_uniform("texture2", 1);

Since OpenGL 4.1 you can alternatively use gl::ProgramUniform

Related