GLFW-RS 只显示黑色方块而不是旋转立方体

GLFW-RS only shows black square instead of rotating cubes

我正在尝试使用 Rust 绑定重新格式化我从 learnopengl.com 创建的 C++ 代码,但它并没有按预期工作。当我应该得到 10 个旋转纹理立方体时,我只得到一个黑色方块。

Here's an image of my output window whenever I run the application.

有人可以帮我找出问题所在吗?我无法理解它,它让我感到困惑。

代码很长,所以这里 link 到存储库,如果这样更容易阅读的话。 Github GLFW Repo

main.rs

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

mod shader;

// use glfw::ffi;
use gl::types::*;
use glfw::{Action, Context, Key};
use glm::*;

use std::ffi::c_void;
use std::mem::size_of;

use shader::shader::Shader;

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(glfw::WindowHint::ContextVersion(4, 3));
    glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(
        glfw::OpenGlProfileHint::Core,
    ));

    let (mut window, events) = glfw
        .create_window(800, 600, "Hello this is window", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    window.set_title("OpenGL Custom App");

    window.set_key_polling(true);
    window.make_current();
    window.set_framebuffer_size_polling(true);

    load_gl_functions(&mut window);

    // ffi::glfwSetWindowSizeCallback(*window, cbfun: Option<GLFWwindowsizefun>);

    // First three verticies, last two texture
    let _vertices: [f32; 180] = [
        -0.5, -0.5, -0.5, 0.0, 0.0, 0.5, -0.5, -0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, 0.5,
        -0.5, 1.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 0.0, -0.5, -0.5, 0.5,
        0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 1.0, 0.5, 0.5, 0.5, 1.0, 1.0, -0.5,
        0.5, 0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, -0.5, 0.5, -0.5,
        1.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0,
        0.0, -0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5,
        -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, 0.5, 0.0, 0.0, 0.5, 0.5, 0.5,
        1.0, 0.0, -0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 1.0, 1.0, 0.5, -0.5, 0.5, 1.0, 0.0,
        0.5, -0.5, 0.5, 1.0, 0.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, 0.5,
        -0.5, 0.0, 1.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0,
        -0.5, 0.5, 0.5, 0.0, 0.0, -0.5, 0.5, -0.5, 0.0, 1.0,
    ];

    let cube_positions: [Vec3; 10] = [
        glm::vec3(0.0, 0.0, 0.0),
        glm::vec3(2.0, 5.0, -15.0),
        glm::vec3(-1.5, -2.2, -2.5),
        glm::vec3(-3.8, -2.0, -12.3),
        glm::vec3(2.4, -0.4, -3.5),
        glm::vec3(-1.7, 3.0, -7.5),
        glm::vec3(1.3, -2.0, -2.5),
        glm::vec3(1.5, 2.0, -2.5),
        glm::vec3(1.5, 0.2, -1.5),
        glm::vec3(-1.3, 1.0, -1.5),
    ];

    let mut vbo: GLuint = 0;
    let mut vao: GLuint = 0;

    let mut texture1: u32 = 0;
    let mut texture2: u32 = 0;

    let shader = Shader::create_shader(
        "src/shaders/vertShader.vert",
        "src/shaders/fragShader.frag",
        &mut window,
    )
    .expect("There was an error creating the program.");

    unsafe {
        gl::Enable(gl::DEPTH_TEST);

        // Vertices pointer

        gl::GenBuffers(1, &mut vbo);
        gl::GenVertexArrays(1, &mut vao);

        gl::BindVertexArray(vao);

        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);

        gl::BufferData(
            gl::ARRAY_BUFFER,
            size_of::<[f32; 180]>() as isize,
            _vertices.as_ptr() as *const c_void,
            gl::STATIC_DRAW,
        );

        // Vertext pointer
        gl::VertexAttribPointer(
            0,
            3,
            gl::FLOAT,
            gl::FALSE,
            5 * size_of::<f32>() as i32,
            0 as *const c_void,
        );
        gl::EnableVertexAttribArray(0);

        // Texture pointer
        gl::VertexAttribPointer(
            1,
            2,
            gl::FLOAT,
            gl::FALSE,
            5 * size_of::<f32>() as i32,
            (3 * size_of::<f32>()) as *const c_void,
        );
        gl::EnableVertexAttribArray(1);

        // Bind textures

        gl::GenTextures(1, &mut texture1 as *mut u32);

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

        gl::TexParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_WRAP_S,
            gl::MIRRORED_REPEAT as i32,
        );
        gl::TexParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_WRAP_R,
            gl::MIRRORED_REPEAT as i32,
        );
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        gl::TexParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_MIN_FILTER,
            gl::LINEAR_MIPMAP_LINEAR as i32,
        );
        let tex1 = image::open("E:\Repos\Rust\RSOpenGL\src\textures\wall.jpg")
            .expect("Failed to load image.")
            .into_rgb();

        gl::TexImage2D(
            gl::TEXTURE_2D,
            0,
            gl::RGB as i32,
            tex1.width() as i32,
            tex1.height() as i32,
            0,
            gl::RGB,
            gl::UNSIGNED_BYTE,
            tex1.as_ptr() as *const c_void,
        );

        gl::GenerateMipmap(gl::TEXTURE_2D);

        // Texture 2
        gl::GenTextures(1, &mut texture2 as *mut u32);

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

        gl::TexParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_WRAP_S,
            gl::MIRRORED_REPEAT as i32,
        );
        gl::TexParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_WRAP_R,
            gl::MIRRORED_REPEAT as i32,
        );
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        gl::TexParameteri(
            gl::TEXTURE_2D,
            gl::TEXTURE_MIN_FILTER,
            gl::LINEAR_MIPMAP_LINEAR as i32,
        );
        let tex2 = image::open("E:\Repos\Rust\RSOpenGL\src\textures\awesomeface.png")
            .expect("Failed to load image.")
            .into_rgb();

        gl::TexImage2D(
            gl::TEXTURE_2D,
            0,
            gl::RGB as i32,
            tex2.width() as i32,
            tex2.height() as i32,
            0,
            gl::RGB,
            gl::UNSIGNED_BYTE,
            tex2.as_ptr() as *const c_void,
        );

        gl::GenerateMipmap(gl::TEXTURE_2D);

        gl::ClearColor(0.2, 0.3, 0.3, 1.0);

        shader.use_shader();
        shader.set_int32("texture1", 0);
        shader.set_int32("texture2", 1);
    }

    let mut last_frame = glfw.get_time();
    while window.should_close() == false {
        let curr_frame: f64 = glfw.get_time();
        let delta_time: f64 = curr_frame - last_frame;
        println!("{}", delta_time);
        last_frame = curr_frame;

        // process input

        unsafe {
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

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

            let projection: glm::Mat4 = glm::ext::perspective::<f32>(
                glm::radians(90.0),
                800 as f32 / 600 as f32,
                0.1,
                100.0,
            );
            shader.set_mat4("projection", projection);

            let view: glm::Mat4 = glm::ext::look_at::<f32>(
                glm::vec3(0.0, 0.0, 3.0),
                glm::vec3(0.0, 0.0, 3.0) + glm::vec3(0.0, 0.0, -1.0),
                glm::vec3(0.0, 1.0, 0.0),
            );
            shader.set_mat4("view", view);
            // println!("{:?}\n{:?}", view, projection);

            shader.use_shader();

            gl::BindVertexArray(vao);
            let mut i: f32 = 0.0;
            for cube in cube_positions.iter() {
                let mut model: glm::Mat4 = glm::mat4(
                    1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
                );
                model = glm::ext::translate(&model, *cube);
                let angle: f32 = 20.0 + i;
                i += 1.0;
                model = glm::ext::rotate(
                    &model,
                    glm::radians(angle) * glfw.get_time() as f32,
                    glm::vec3(1.0, 0.3, 0.5),
                );
                shader.set_mat4("model", model);
                // println!("{:?}", model);

                gl::DrawArrays(gl::TRIANGLES, 0, 36);
            }
        }

        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }
        window.swap_buffers();
    }

    unsafe {
        gl::DeleteVertexArrays(1, &vao);
        gl::DeleteBuffers(1, &vbo);

        // glfw::ffi::glfwTerminate(); apparently not necessary
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    match event {
        glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => window.set_should_close(true),
        _ => {}
    }
}

fn load_gl_functions(window: &mut glfw::Window) {
    gl::ClearColor::load_with(|_s| window.get_proc_address("glClearColor"));
    gl::Clear::load_with(|_s| window.get_proc_address("glClear"));
    gl::GenBuffers::load_with(|_s| window.get_proc_address("glGenBuffers"));
    gl::GenVertexArrays::load_with(|_s| window.get_proc_address("glGenVertexArrays"));
    gl::BindBuffer::load_with(|_s| window.get_proc_address("glBindBuffer"));
    gl::BufferData::load_with(|_s| window.get_proc_address("glBufferData"));
    gl::VertexAttribPointer::load_with(|_s| window.get_proc_address("glVertexAttribPointer"));
    gl::EnableVertexAttribArray::load_with(|_s| {
        window.get_proc_address("glEnableVertexAttribArray")
    });
    gl::BindVertexArray::load_with(|_s| window.get_proc_address("glBindVertexArray"));

    gl::DeleteVertexArrays::load_with(|_s| window.get_proc_address("glDeleteVertexArrays"));
    gl::DeleteBuffers::load_with(|_s| window.get_proc_address("glDeleteBuffers"));

    gl::GenTextures::load_with(|_s| window.get_proc_address("glGenTextures"));
    gl::TexParameteri::load_with(|_s| window.get_proc_address("glTexParameteri"));
    gl::TexImage2D::load_with(|_s| window.get_proc_address("glTexImage2D"));
    gl::BindTexture::load_with(|_s| window.get_proc_address("glBindTexture"));
    gl::ActiveTexture::load_with(|_s| window.get_proc_address("glActiveTexture"));
    gl::GenerateMipmap::load_with(|_s| window.get_proc_address("glGenerateMipmap"));

    gl::Enable::load_with(|_s| window.get_proc_address("glEnable"));
    gl::DrawArrays::load_with(|_s| window.get_proc_address("glDrawArrays"));
}

shader.rs

extern crate gl;
extern crate glfw;
extern crate glm;

pub mod shader {
    pub struct Shader {
        pub id: u32,
    }

    impl Shader {
        pub fn create_shader(vert_file_path: &str, frag_file_path: &str, window: &mut glfw::Window) -> std::result::Result<Shader, std::io::Error> {
            if gl::CreateProgram::is_loaded() == false {
                let result = Shader::load_gl_procs(window);
                if result == false {
                    return Err(std::io::Error::new(
                        std::io::ErrorKind::Other,
                        "ERROR::SHADER::CANNOT_LOAD_PROGRAMS",
                    ));
                }
            }

            let vert_text = std::fs::read_to_string(vert_file_path).expect("Unable to read vert file");
            let vert_text_ptr = vert_text.as_ptr() as *const *const gl::types::GLchar;

            let frag_text = std::fs::read_to_string(frag_file_path).expect("Unable to read frag file");
            let frag_text_ptr = frag_text.as_ptr() as *const *const gl::types::GLchar;
            //println!("{:?} \n{:?}", vert_text_ptr, frag_text_ptr);

            let id: gl::types::GLuint;

            unsafe {
                let vert_shader = gl::CreateShader(gl::VERTEX_SHADER);
                gl::ShaderSource(vert_shader, 1, vert_text_ptr, &0);
                gl::CompileShader(vert_shader);

                /*  STATUS_ACCESS_VIOLATION error
                let mut success: i32;
                let mut info_log: [gl::types::GLchar; 512] = [0; 512];

                gl::GetShaderiv(vert_shader, gl::COMPILE_STATUS, success as *mut i32);
                println!("{:?}", success);

                if success == 0 {
                    gl::GetShaderInfoLog(vert_shader, 512, 0 as *mut gl::types::GLsizei, &mut info_log[0]);

                    for i in info_log.iter() {
                        print!("{}", i);
                    }
                } */

                let frag_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
                gl::ShaderSource(frag_shader, 1, frag_text_ptr, &0);
                gl::CompileShader(frag_shader);

                id = gl::CreateProgram();

                gl::AttachShader(id, vert_shader);
                gl::AttachShader(id, frag_shader);
                gl::LinkProgram(id);

                gl::DeleteShader(vert_shader);
                gl::DeleteShader(frag_shader);
            }

            let created_shader: Shader = Shader { id: id };

            return Ok(created_shader);
        }

        pub fn load_gl_procs(window: &mut glfw::Window) -> bool {
            gl::CreateShader::load_with(|_s| window.get_proc_address("glCreateShader"));
            gl::ShaderSource::load_with(|_s| window.get_proc_address("glShaderSource"));
            gl::CompileShader::load_with(|_s| window.get_proc_address("glCompileShader"));
            gl::GetShaderiv::load_with(|_s| window.get_proc_address("glGetShaderiv"));
            gl::CreateProgram::load_with(|_s| window.get_proc_address("glCreateProgram"));
            gl::AttachShader::load_with(|_s| window.get_proc_address("glAttachShader"));
            gl::LinkProgram::load_with(|_s| window.get_proc_address("glLinkProgram"));
            gl::GetProgramiv::load_with(|_s| window.get_proc_address("glGetProgramiv"));
            gl::GetShaderInfoLog::load_with(|_s| window.get_proc_address("glGetShaderInfoLog"));
            gl::GetProgramInfoLog::load_with(|_s| window.get_proc_address("glGetProgramInfoLog"));
            gl::DeleteShader::load_with(|_s| window.get_proc_address("glDeleteShader"));
            gl::UseProgram::load_with(|_s| window.get_proc_address("glUseProgram"));

            gl::Uniform1i::load_with(|_s| window.get_proc_address("glUniform1i"));
            gl::Uniform1f::load_with(|_s| window.get_proc_address("glUniform1f"));
            gl::UniformMatrix4fv::load_with(|_s| window.get_proc_address("glUniformMatrix4fv"));
            gl::GetUniformLocation::load_with(|_s| window.get_proc_address("glGetUniformLocation"));


            // TODO Check to see if all of these are loaded

            return true;
        }

        pub unsafe fn use_shader(&self) {
            gl::UseProgram(self.id as gl::types::GLuint);
        }

        pub unsafe fn set_bool(&self, name: &str, value: bool) {
            gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr() as *const gl::types::GLchar), value as gl::types::GLint);
        }

        pub unsafe fn set_int32(&self, name: &str, value: i32) {
            gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr() as *const gl::types::GLchar), value as gl::types::GLint);
        }

        pub unsafe fn set_float32(&self, name: &str, value: f32) {
            gl::Uniform1f(gl::GetUniformLocation(self.id, name.as_ptr() as *const gl::types::GLchar), value as gl::types::GLfloat);
        }

        pub unsafe fn set_mat4(&self, name: &str, value: glm::Mat4) {
            gl::UniformMatrix4fv(gl::GetUniformLocation(self.id, name.as_ptr() as *const gl::types::GLchar), 1, gl::FALSE, &value[0][0]);
        }
    }
}

vertShader.vert

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    TexCoord = aTexCoord;
}

fragShader.frag

#version 330 core

out vec4 FragColor;

in vec2 TexCoord;

uniform sampler2D texture1;
uniform sampler2D texture2;

void main()
{
//   FragColor = vec4(ourColor, 1.0f);
    FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.5);
}

我的程序实际上有两个主要问题,都是关于 CString 的。

问题 1:OpenGL 无法创建程序,因为我发送给它的文本没有空终止字符,因此必须将其重铸为带有一个的 CString。

let v_shader_code = CString::new(vert_text.as_bytes()).unwrap();
let f_shader_code = CString::new(frag_text.as_bytes()).unwrap();

问题 2:"set_*()" 函数不起作用,因为该名称作为 &str 传递,没有空终止符。这也必须转换为 c 字符串。

pub unsafe fn set_bool(&self, name: &str, value: bool) {
    gl::Uniform1i(gl::GetUniformLocation(self.id, CString::new(name).expect("Error converting &str to CString").as_c_str().as_ptr()), value as i32);
}