使用各种代码示例,我创建了一个简单的OpenGL应用程序,项目依赖项如下:

[dependencies]
epoxy = "0.1.0"
gl = "0.14.0"
gtk = { version = "0.7.3", package = "gtk4", features = ["v4_12"] }
libloading = "0.8.1"

逻辑也很简单:使用GTK+ v4.12和OpenGL上下文初始化一个窗口,并try 绘制一个三角形.

main.rs

mod renderer;

use gtk::prelude::*;
use gtk::{glib, Application, ApplicationWindow};
use renderer::{on_render, on_realize};

const APP_ID: &str = "com.noobie.teapot";
const APP_NAME: &str = "Teapot";

fn main() -> glib::ExitCode {
    init_gl();
    // Create a new application
    let app = Application::builder()
        .application_id(APP_ID)
        .build();

    // Connect to "activate" signal of `app`
    app.connect_activate(on_activate);

    // Run the application
    app.run()
}

fn init_gl() {
    #[cfg(target_os = "macos")]
    let library = unsafe { libloading::os::unix::Library::new("libepoxy.0.dylib") }.unwrap();
    #[cfg(all(unix, not(target_os = "macos")))]
    let library = unsafe { libloading::os::unix::Library::new("libepoxy.so.0") }.unwrap();
    #[cfg(windows)]
    let library = libloading::os::windows::Library::open_already_loaded("epoxy-0.dll").unwrap();

    epoxy::load_with(|name| {
        unsafe { library.get::<_>(name.as_bytes()) }
        .map(|symbol| *symbol)
            .unwrap_or(std::ptr::null())
    });
    gl::load_with(|s| epoxy::get_proc_addr(s));
}

fn on_activate(app: &Application) {
    // Create a window and set the title
    let window = ApplicationWindow::builder()
        .application(app)
        .title(APP_NAME)
        .default_width(800)
        .default_height(600)
        .build();

    let container = gtk::Paned::builder()
        .orientation(gtk::Orientation::Vertical)
        .shrink_end_child(true)
        .build();

    let gl_area = gtk::GLArea::builder()
        .auto_render(false)
        .height_request(8)
        .build();
    gl_area.connect_realize(on_realize);
    gl_area.connect_render(on_render);
    container.set_start_child(Some(&gl_area));

    let grid_view = gtk::GridView::builder()
        .height_request(4)
        .build();
    container.set_end_child(Some(&grid_view));

    window.set_child(Some(&container));
    // Present window
    window.present();
}

renderer.rs

use std::mem::{size_of_val, size_of};

use gtk::prelude::*;
use gtk::{glib::Propagation, gdk::GLContext};

type Vertex = [f32; 3];
const VERTICES: [Vertex; 3] = [
        [-0.5, -0.5, 0.0], 
        [0.5, -0.5, 0.0], 
        [0.0, 0.5, 0.0]
    ];
const VERT_SHADER: &str = r#"#version 330 core
        layout (location = 0) in vec3 pos;
        void main() {
            gl_Position = vec4(pos.x, pos.y, pos.z, 1.0);
        }
    "#;
const FRAG_SHADER: &str = r#"#version 330 core
        out vec4 final_color;
    
        void main() {
        final_color = vec4(1.0, 0.5, 0.2, 1.0);
        }
    "#;

pub fn on_realize(_gl_area: &gtk::GLArea) {
}

pub fn on_render(_gl_area: &gtk::GLArea, _ctx: &GLContext) -> Propagation {
    unsafe {
        gl::ClearColor(0.3, 0.3, 0.3, 1.0);

        let mut vao = 0;
        gl::GenVertexArrays(1, &mut vao);
        assert_ne!(vao, 0);

        let mut vbo = 0;
        gl::GenBuffers(1, &mut vbo);
        assert_ne!(vbo, 0);

        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER, size_of_val(&VERTICES) as isize, VERTICES.as_ptr().cast(), gl::STATIC_DRAW);
        gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, size_of::<Vertex>().try_into().unwrap(), 0 as *const _);
        gl::EnableVertexAttribArray(0);

        let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
        assert_ne!(vertex_shader, 0);

        gl::ShaderSource(
                vertex_shader,
                1,
                &(VERT_SHADER.as_bytes().as_ptr().cast()),
                &(VERT_SHADER.len().try_into().unwrap()),
            );

        gl::CompileShader(vertex_shader);

        let mut success = 0;
        gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success);

        if success == 0 {
            let mut v: Vec<u8> = Vec::with_capacity(1024);
            let mut log_len = 0_i32;
            gl::GetShaderInfoLog(
                    vertex_shader,
                    1024,
                    &mut log_len,
                    v.as_mut_ptr().cast(),
                );
            v.set_len(log_len.try_into().unwrap());
            panic!("Vertex Compile Error: {}", String::from_utf8_lossy(&v));
        }

        let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
        assert_ne!(fragment_shader, 0);

        gl::ShaderSource(
                fragment_shader,
                1,
                &(FRAG_SHADER.as_bytes().as_ptr().cast()),
                &(FRAG_SHADER.len().try_into().unwrap()),
            );
        gl::CompileShader(fragment_shader);

        gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success);
        if success == 0 {
            let mut v: Vec<u8> = Vec::with_capacity(1024);
            let mut log_len = 0_i32;
            gl::GetShaderInfoLog(
                    fragment_shader,
                    1024,
                    &mut log_len,
                    v.as_mut_ptr().cast(),
                );
            v.set_len(log_len.try_into().unwrap());
            panic!("Fragment Compile Error: {}", String::from_utf8_lossy(&v));
        }

        let shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::LinkProgram(shader_program);

        let mut success = 0;
        gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success);
        if success == 0 {
            let mut v: Vec<u8> = Vec::with_capacity(1024);
            let mut log_len = 0_i32;
            gl::GetProgramInfoLog(
                    shader_program,
                    1024,
                    &mut log_len,
                    v.as_mut_ptr().cast(),
                );
            v.set_len(log_len.try_into().unwrap());
            panic!("Program Link Error: {}", String::from_utf8_lossy(&v));
        }

        gl::DeleteShader(vertex_shader);
        gl::DeleteShader(fragment_shader);

        gl::UseProgram(shader_program);

        gl::Clear(gl::COLOR_BUFFER_BIT);
        gl::DrawArrays(gl::TRIANGLES, 0, 3);

        _gl_area.queue_draw();
    }

    return Propagation::Proceed;
}

However, when I launch my program it just shows a solid gray color:
Screenshot

我对OpenGL一窍不通,所以我甚至不知道问题出在哪里.控制台输出中没有任何错误.

推荐答案

您只看到灰色的原因是因为这是您当前的清晰 colored颜色 ,而三角形不是在上面绘制的.

据我所知,您当前的实现存在多个问题,我不确定是否有必要一一查看所有这些问题.

如果你只是想让它发挥作用,这里有一个非常基本的renderer.rs看起来会是什么样子的样本:

use gl::types::*;
use std::ffi::CString;
use std::mem;
use std::ptr;

use gtk::{gdk::GLContext, glib::Propagation};

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];

// Shader sources
static VS_SRC: &'static str = "
#version 150
in vec2 position;

void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}";

static FS_SRC: &'static str = "
#version 150
out vec4 out_color;

void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
}";

pub fn on_realize(_gl_area: &gtk::GLArea) {}

pub fn on_render(_gl_area: &gtk::GLArea, _ctx: &GLContext) -> Propagation {
    // Create GLSL shaders
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

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

    unsafe {
        // Create Vertex Array Object
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(
            gl::ARRAY_BUFFER,
            (VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
            mem::transmute(&VERTEX_DATA[0]),
            gl::STATIC_DRAW,
        );

        // Use shader program
        let out_color_cstring = CString::new("out_color").unwrap();
        gl::UseProgram(program);
        gl::BindFragDataLocation(program, 0, out_color_cstring.as_ptr());

        // Specify the layout of the vertex data
        let position_cstring = CString::new("position").unwrap();
        let pos_attr = gl::GetAttribLocation(program, position_cstring.as_ptr());
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(
            pos_attr as GLuint,
            2,
            gl::FLOAT,
            gl::FALSE as GLboolean,
            0,
            ptr::null(),
        );

        // Clear the screen to black
        gl::ClearColor(0.3, 0.3, 0.3, 1.0);
        gl::Clear(gl::COLOR_BUFFER_BIT);
        // Draw a triangle from the 3 vertices
        gl::DrawArrays(gl::TRIANGLES, 0, 3);
    }

    return Propagation::Proceed;
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl::CreateShader(ty);
        // Attempt to compile the shader
        let c_str = CString::new(src.as_bytes()).unwrap();
        gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(
                shader,
                len,
                ptr::null_mut(),
                buf.as_mut_ptr() as *mut GLchar,
            );
            panic!(
                "{}",
                std::str::from_utf8(&buf)
                    .ok()
                    .expect("ShaderInfoLog not valid utf8")
            );
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    unsafe {
        let program = gl::CreateProgram();
        gl::AttachShader(program, vs);
        gl::AttachShader(program, fs);
        gl::LinkProgram(program);
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(
                program,
                len,
                ptr::null_mut(),
                buf.as_mut_ptr() as *mut GLchar,
            );
            panic!(
                "{}",
                std::str::from_utf8(&buf)
                    .ok()
                    .expect("ProgramInfoLog not valid utf8")
            );
        }
        program
    }
}

这在很大程度上是基于gl-rs的官方triangle example.

然而,@BDL的 comments 当然仍然适用,这里不考虑,这就是为什么我建议你go 看看(基于glium的)OpenGL example of gtk4-rs.

Rust相关问答推荐

在Rust中创建可变片段的可变片段的最有效方法是什么?

为什么我不能从带有字符串的 struct 的引用迭代器中收集VEC<;&;str&>?

在UdpSocket上使用sendto时的隐式套接字绑定

为什么TcpListener的文件描述符和生成的TcpStream不同?

rust 蚀生命周期 不匹配-不一定超过此处定义的生命周期

Rust函数的返回值不能引用局部变量或临时变量

正在将带有盒的异步特征迁移到新的异步_fn_in_特征功能

对reqwest提供的这种嵌套JSON struct 进行反序列化

Rust面向对象设计模式

如何获取光标下的像素 colored颜色 ?

如何轮询 Pin>?

这是什么:`impl Trait for T {}`?

类型生命周期绑定的目的是什么?

信号量释放后 Rust 输出挂起线程

Rust 1.70 中未找到 Trait 实现

如何为已实现其他相关 std trait 的每个类型实现一个 std Trait

Rust编译器通过哪些规则来确保锁被释放?

Rust 中的生命周期:borrow 的 mut 数据

是否可以在 Rust 中的特定字符上实现特征?

在 Rust 中组合特征的不同方法是否等效?