|
// OpenGL + SDL2 example. Based on |
|
// https://github.com/brendanzab/gl-rs/blob/master/gl/examples/triangle.rs |
|
// but replacing glutin with SDL2. |
|
|
|
extern crate sdl2; |
|
extern crate gl; |
|
|
|
use sdl2::video::GLProfile; |
|
use sdl2::event::Event; |
|
use sdl2::keyboard::Keycode; |
|
use gl::types::*; |
|
use std::mem; |
|
use std::ptr; |
|
use std::str; |
|
use std::ffi::CString; |
|
|
|
// 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 = include_str!("triangle.vert"); |
|
static FS_SRC: &'static str = include_str!("triangle.frag"); |
|
|
|
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!("{}", 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!("{}", str::from_utf8(&buf).ok().expect("ProgramInfoLog not valid utf8")); |
|
} |
|
program |
|
} } |
|
|
|
fn main() { |
|
let sdl_context = sdl2::init().unwrap(); |
|
let video_subsystem = sdl_context.video().unwrap(); |
|
let gl_attr = video_subsystem.gl_attr(); |
|
gl_attr.set_context_profile(GLProfile::Core); |
|
gl_attr.set_context_flags().debug().set(); |
|
gl_attr.set_context_version(3, 3); |
|
|
|
let window = video_subsystem |
|
.window("rust-sdl2 opengl triangle", 800, 600) |
|
.opengl() |
|
.resizable() |
|
.build() |
|
.unwrap(); |
|
|
|
gl::load_with(|name| video_subsystem.gl_get_proc_address(name) as *const _); |
|
|
|
let gl_context = window.gl_create_context().unwrap(); |
|
window.gl_make_current(&gl_context).unwrap(); |
|
|
|
// 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 |
|
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()); |
|
} |
|
|
|
let mut event_pump = sdl_context.event_pump().unwrap(); |
|
|
|
unsafe { |
|
gl::ClearColor(0.0, 0.0, 0.0, 1.0); |
|
} |
|
|
|
'running: loop { |
|
for event in event_pump.poll_iter() { |
|
match event { |
|
Event::Quit { .. } | |
|
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => break 'running, |
|
_ => {} |
|
} |
|
} |
|
|
|
unsafe { |
|
gl::Clear(gl::COLOR_BUFFER_BIT); |
|
gl::DrawArrays(gl::TRIANGLES, 0, 3); |
|
} |
|
window.gl_swap_window(); |
|
} |
|
} |