extern crate sdl2; extern crate gl; extern crate image; use sdl2::video::GLProfile; use gl::types::*; use image::GenericImageView; static WIN_W : u32 = 800; static WIN_H : u32 = 800; static VERTEX_DATA : [GLfloat; 12] = [ -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5 ]; static TEX_DATA : [GLfloat; 12] = [ 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0 ]; static NUM_VERTICES : GLint = 6; static VERTEX_LOC : u32 = 0; static TEX_LOC : u32 = 1; static VS : &'static str = "#version 130\n\ in vec4 pos;\n\ in vec2 in_tex_coord;\n\ out vec2 tex_coord;\n\ void main() {\n\ gl_Position = pos;\n\ tex_coord = in_tex_coord;\n\ }"; static FS : &'static str = "#version 130\n\ uniform sampler2D tex;\n\ in vec2 tex_coord;\n\ out vec4 color;\n\ void main() {\n\ color = texture2D(tex, tex_coord);\n\ }"; fn compile_sdr(src: &str, stage:GLenum) -> GLuint { let shader; unsafe { shader = gl::CreateShader(stage); let s = std::ffi::CString::new(src).expect("CString::new failed");; gl::ShaderSource(shader, 1, &s.as_ptr(), std::ptr::null()); gl::CompileShader(shader); // status let mut status = gl::FALSE as GLint; gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status); // error handling if status != (gl::TRUE as GLint) { let mut len = 0; gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len); let mut buf: Vec = Vec::with_capacity((len + 1) as usize); buf.extend([b' '].iter().cycle().take(len as usize)); let err: std::ffi::CString = std::ffi::CString::from_vec_unchecked(buf); gl::GetShaderInfoLog(shader, len, std::ptr::null_mut(), err.as_ptr() as *mut GLchar); println!("{}", err.to_str().unwrap()); } } shader } fn link_sdr_prog(vs: GLuint, fs: GLuint) -> GLuint { unsafe { let sdr_prog = gl::CreateProgram(); gl::AttachShader(sdr_prog, vs); gl::AttachShader(sdr_prog, fs); gl::LinkProgram(sdr_prog); let mut status = gl::FALSE as GLint; gl::GetProgramiv(sdr_prog, gl::LINK_STATUS, &mut status); if status != (gl::TRUE as GLint) { let mut len: GLint = 0; gl::GetProgramiv(sdr_prog, gl::INFO_LOG_LENGTH, &mut len); let mut buf: Vec = Vec::with_capacity((len + 1) as usize); buf.extend([b' '].iter().cycle().take(len as usize)); let err: std::ffi::CString = std::ffi::CString::from_vec_unchecked(buf); gl::GetProgramInfoLog(sdr_prog, len, std::ptr::null_mut(), err.as_ptr() as *mut GLchar); println!("{}", err.to_str().unwrap()); } sdr_prog } } fn gen_tex(fname : String, _id : &mut GLuint) { let img : image::DynamicImage = image::open(&std::path::Path::new(&fname)).ok().expect("Can't open image.\n"); let (_w, _h) = img.dimensions(); unsafe { gl::GenTextures(1, _id); gl::BindTexture(gl::TEXTURE_2D, *_id); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as i32, _w as i32, _h as i32, 0, gl::RGBA, gl::UNSIGNED_BYTE, img.to_rgba().into_raw().as_ptr() as *const std::ffi::c_void); gl::BindTexture(gl::TEXTURE_2D, 0); } } fn main() { //TODO FIXME init let sdl_ctx = sdl2::init().unwrap(); let vid_sys = sdl_ctx.video().unwrap(); let gl_attr = vid_sys.gl_attr(); gl_attr.set_context_profile(GLProfile::Core); let win = vid_sys .window("foobar", WIN_W, WIN_H) .opengl() // add opengl flag .resizable() .build() .unwrap(); let _gl_ctx = win.gl_create_context().unwrap(); let _gl = gl::load_with(|s| vid_sys.gl_get_proc_address(s) as *const std::os::raw::c_void); let mut vao = 1; let mut vbo_pos = 1; let mut vbo_tex = 2; let sprog; let fs; let vs; let mut tex_igalia : GLuint = 1; let mut tex_guadec : GLuint = 2; let mut tex_sel = tex_igalia; let mut uloc_stex : GLint = -1; gen_tex("data/igalia.png".to_string(), &mut tex_igalia); gen_tex("data/guadec.png".to_string(), &mut tex_guadec); unsafe { gl::ClearColor(0.0, 0.0, 0.0, 1.0); gl::Enable(gl::BLEND); gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); gl::GenVertexArrays(1, &mut vao); gl::BindVertexArray(vao); gl::GenBuffers(1, &mut vbo_pos); gl::BindBuffer(gl::ARRAY_BUFFER, vbo_pos); gl::BufferData(gl::ARRAY_BUFFER, (VERTEX_DATA.len() * std::mem::size_of::()) as GLsizeiptr, std::mem::transmute(&VERTEX_DATA[0]), gl::STATIC_DRAW); gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::GenBuffers(1, &mut vbo_tex); gl::BindBuffer(gl::ARRAY_BUFFER, vbo_tex); gl::BufferData(gl::ARRAY_BUFFER, (TEX_DATA.len() * std::mem::size_of::()) as GLsizeiptr, std::mem::transmute(&TEX_DATA[0]), gl::STATIC_DRAW); gl::BindBuffer(gl::ARRAY_BUFFER, 0); vs = compile_sdr(VS, gl::VERTEX_SHADER); fs = compile_sdr(FS, gl::FRAGMENT_SHADER); sprog = link_sdr_prog(vs, fs); gl::UseProgram(sprog); } let mut event_pump = sdl_ctx.event_pump().unwrap(); 'main: loop { for event in event_pump.poll_iter() { // handle user input here match event { sdl2::event::Event::Quit {..} | sdl2::event::Event::KeyDown {keycode: Some(sdl2::keyboard::Keycode::Escape), ..} => break 'main, sdl2::event::Event::KeyDown {keycode: Some(sdl2::keyboard::Keycode::I), ..} => tex_sel = tex_igalia, sdl2::event::Event::KeyDown {keycode: Some(sdl2::keyboard::Keycode::G), ..} => tex_sel = tex_guadec, _ => {}, } } //TODO FIXME: display unsafe { let uni_str = std::ffi::CString::new("tex").unwrap(); uloc_stex = gl::GetUniformLocation(sprog, uni_str.as_ptr()); if uloc_stex > -1 { gl::Uniform1i(uloc_stex, tex_sel as i32); } gl::Clear(gl::COLOR_BUFFER_BIT); gl::Viewport(0, 0, WIN_W as i32, WIN_H as i32); /* pos */ gl::EnableVertexAttribArray(VERTEX_LOC); gl::BindBuffer(gl::ARRAY_BUFFER, vbo_pos); gl::VertexAttribPointer(VERTEX_LOC, 2, gl::FLOAT, gl::FALSE, 0 as i32, std::ptr::null()); /* tex coords */ gl::EnableVertexAttribArray(TEX_LOC); gl::BindBuffer(gl::ARRAY_BUFFER, vbo_tex); gl::VertexAttribPointer(TEX_LOC, 2, gl::FLOAT, gl::FALSE, 0 as i32, std::ptr::null()); gl::ActiveTexture(gl::TEXTURE0 + tex_sel); gl::BindTexture(gl::TEXTURE_2D, tex_sel); gl::DrawArrays(gl::TRIANGLES, 0, NUM_VERTICES); } win.gl_swap_window(); } //TODO FIXME: cleanup unsafe { gl::DeleteProgram(sprog); gl::DeleteShader(vs); gl::DeleteShader(fs); gl::DeleteBuffers(1, &vbo_pos); gl::DeleteBuffers(1, &vbo_tex); gl::DeleteVertexArrays(1, &vao); gl::DeleteTextures(1, &tex_igalia); gl::DeleteTextures(1, &tex_guadec); } }