use gl;
use gl::types::{GLenum, GLint, GLuint};
use std::fs::File;
use std::io::Read;
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<u8>, filename: &str);
}
#[allow(dead_code)]
pub struct FilesystemResourceLoader;
impl ResourceLoader for FilesystemResourceLoader {
fn slurp(&self, dest: &mut Vec<u8>, 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);
}
}