// examples/common/mod.rs // // OpenGL convenience wrappers used in the examples. use gl; use gl::types::{GLchar, GLenum, GLint, GLuint}; use std::fs::File; use std::io::Read; use std::os::raw::c_void; use std::ptr; use surfman::GLApi; pub struct Program { pub object: GLuint, #[allow(dead_code)] vertex_shader: Shader, #[allow(dead_code)] fragment_shader: Shader, } impl Program { pub fn new(vertex_shader: Shader, fragment_shader: Shader) -> Program { unsafe { let program = gl::CreateProgram(); ck(); gl::AttachShader(program, vertex_shader.object); ck(); gl::AttachShader(program, fragment_shader.object); ck(); gl::LinkProgram(program); ck(); Program { object: program, vertex_shader, fragment_shader, } } } } pub struct Shader { object: GLuint, } impl Shader { pub fn new( name: &str, kind: ShaderKind, gl_api: GLApi, gl_texture_target: GLenum, resource_loader: &dyn ResourceLoader, ) -> Shader { let mut source = vec![]; match gl_api { GLApi::GL => source.extend_from_slice(b"#version 330\n"), GLApi::GLES => source.extend_from_slice(b"#version 300 es\n"), } match gl_texture_target { gl::TEXTURE_2D => {} gl::TEXTURE_RECTANGLE => source.extend_from_slice(b"#define SAMPLER_RECT\n"), _ => {} } resource_loader.slurp(&mut source, &format!("{}.{}.glsl", name, kind.extension())); unsafe { let shader = gl::CreateShader(kind.to_gl()); ck(); gl::ShaderSource( shader, 1, &(source.as_ptr().cast()), &(source.len() as GLint), ); ck(); gl::CompileShader(shader); ck(); let mut compile_status = 0; gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut compile_status); ck(); if compile_status != gl::TRUE as GLint { let mut info_log_length = 0; gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut info_log_length); let mut info_log = vec![0; info_log_length as usize + 1]; gl::GetShaderInfoLog( shader, info_log_length, ptr::null_mut(), info_log.as_mut_ptr() as *mut _, ); eprintln!( "Failed to compile shader:\n{}", String::from_utf8_lossy(&info_log) ); panic!("Shader compilation failed!"); } debug_assert_eq!(compile_status, gl::TRUE as GLint); Shader { object: shader } } } } pub struct Buffer { pub object: GLuint, } impl Buffer { pub fn from_data(data: &[u8]) -> Buffer { unsafe { let mut buffer = 0; gl::GenBuffers(1, &mut buffer); ck(); gl::BindBuffer(gl::ARRAY_BUFFER, buffer); ck(); gl::BufferData( gl::ARRAY_BUFFER, data.len() as isize, data.as_ptr().cast(), gl::STATIC_DRAW, ); ck(); Buffer { object: buffer } } } } #[derive(Clone, Copy, PartialEq, Debug)] pub enum ShaderKind { Vertex, Fragment, } impl ShaderKind { fn extension(self) -> &'static str { match self { ShaderKind::Vertex => "vs", ShaderKind::Fragment => "fs", } } fn to_gl(self) -> GLenum { match self { ShaderKind::Vertex => gl::VERTEX_SHADER, ShaderKind::Fragment => gl::FRAGMENT_SHADER, } } } pub trait ResourceLoader { fn slurp(&self, dest: &mut Vec, filename: &str); } #[allow(dead_code)] pub struct FilesystemResourceLoader; impl ResourceLoader for FilesystemResourceLoader { fn slurp(&self, dest: &mut Vec, filename: &str) { let path = format!("resources/examples/{}", filename); File::open(&path) .expect("Failed to open file!") .read_to_end(dest) .unwrap(); } } pub fn ck() { unsafe { debug_assert_eq!(gl::GetError(), gl::NO_ERROR); } }