use gl::types::{GLboolean, GLchar, GLenum, GLfloat, GLint, GLsizeiptr, GLuint}; use safex::glx::*; use safex::xlib::*; use std::ffi::{c_void, CString}; use std::{mem, ptr}; // 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 140 in vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); }"; static FS_SRC: &'static str = " #version 140 out vec4 out_color; void main() { out_color = vec4(1.0, 1.0, 1.0, 1.0); }"; 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 } } fn main() { let display = Display::open(None); let screen = Screen::default(&display); let vi = glx_choose_visual( &display, &mut [GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, GLX_NONE], ) .unwrap(); let window = Window::new_with_glx(&display, &screen, &vi, None, 0, 0, 200, 200, 1, 0, 0, &vi).unwrap(); let glc = GLXContext::create(&display, &vi, None, gl::TRUE as i32); glx_make_current(&display, &window, &glc); gl::load_with(|string| glc.get_proc_address(string).unwrap() as *mut c_void); 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::()) as GLsizeiptr, mem::transmute(&VERTEX_DATA[0]), gl::STATIC_DRAW, ); // Use shader program gl::UseProgram(program); gl::BindFragDataLocation(program, 0, CString::new("out_color").unwrap().as_ptr()); // Specify the layout of the vertex data let pos_attr = gl::GetAttribLocation(program, CString::new("position").unwrap().as_ptr()); gl::EnableVertexAttribArray(pos_attr as GLuint); gl::VertexAttribPointer( pos_attr as GLuint, 2, gl::FLOAT, gl::FALSE as GLboolean, 0, ptr::null(), ); } window.map(&display); window.run(|event, control_flow| match event { WindowEvent::Expose => { unsafe { gl::Viewport(0, 0, 100, 100); 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); } window.glx_swap_buffers(); } }) }