#![crate_name = "glhelper"]
#![crate_type = "lib"]
extern crate gl;
use self::gl::types::{GLenum, GLint, GLuint, GLchar, GLfloat, GLsizeiptr};
use std::ptr;
use std::str;
use std::ffi::CString;
use std::mem;
pub static QUAD_DATA: [GLfloat; 20] =
[
-1., 1., 0.0, 0.0, 0.0,
1., 1., 0.0, 1.0, 0.0,
-1., -1., 0.0, 0.0, 1.0,
1., -1., 0.0, 1.0, 1.0
];
pub fn compile_shader(src: &'static str, shader_type: GLenum) -> GLuint
{
let shader;
unsafe {
shader = gl::CreateShader(shader_type);
let c_str = CString::new(src.as_bytes()).unwrap();
gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
gl::CompileShader(shader);
let mut status = gl::FALSE as GLint;
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
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); gl::GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
panic!("{}", str::from_utf8(&buf).ok().expect("ShaderInfoLog invalid UTF8"));
}
}
shader
}
pub fn link_program(vs: GLuint, fs: GLuint) -> GLuint
{
unsafe {
let program = gl::CreateProgram();
gl::AttachShader(program, vs);
gl::AttachShader(program, fs);
gl::LinkProgram(program);
let mut status = gl::FALSE as GLint;
gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
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); gl::GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
panic!("{}", str::from_utf8(&buf).ok().expect("ProgramInfoLog invalid UTF8"));
}
program
}
}
pub fn load_program(vsrc: &'static str, fsrc: &'static str, shaders: &mut Vec<GLuint>) -> GLuint
{
let vs = compile_shader(vsrc, gl::VERTEX_SHADER);
let fs = compile_shader(fsrc, gl::FRAGMENT_SHADER);
let program = link_program(vs, fs);
shaders.push(vs);
shaders.push(fs);
program
}
pub fn load_program_with_shader_outs(vsrc: &'static str, vout: &mut GLuint, fsrc: &'static str, fout: &mut GLuint) -> GLuint
{
let vs = compile_shader(vsrc, gl::VERTEX_SHADER);
let fs = compile_shader(fsrc, gl::FRAGMENT_SHADER);
let program = link_program(vs, fs);
*vout = vs;
*fout = fs;
program
}
pub fn check_gl_error(file: &'static str, line: u32)
{
unsafe
{
loop
{
let err_str: &'static str = match gl::GetError()
{
gl::NO_ERROR => { break },
gl::INVALID_OPERATION => { "INVALID_OPERATION" },
gl::INVALID_ENUM => { "INVALID_ENUM" },
gl::INVALID_VALUE => { "INVALID_VALUE" },
gl::OUT_OF_MEMORY => { "OUT_OF_MEMROY" },
gl::INVALID_FRAMEBUFFER_OPERATION => { "INVALID_FRAMEBUFFER_OPERATION" }
_ => { "" }
};
println!("GL_{}: {}, {}", err_str, file, line);
}
}
}
pub const STRIDE: usize = 16;
pub fn add_path_line(path: &[(f32, f32)], path_edges: usize, line_program: GLuint, line_vao: GLuint, line_vbo: GLuint)
{
let mut line_data: Vec<f32> = Vec::with_capacity(path_edges*STRIDE);
unsafe
{
for i in 0..path_edges
{
let normalx = path[i+1].1 - path[i].1;
let normaly = path[i].0 - path[i+1].0;
line_data.push(path[i].0);
line_data.push(path[i].1);
line_data.push(-normalx);
line_data.push(-normaly);
line_data.push(path[i].0);
line_data.push(path[i].1);
line_data.push(normalx);
line_data.push(normaly);
line_data.push(path[i+1].0);
line_data.push(path[i+1].1);
line_data.push(-normalx);
line_data.push(-normaly);
line_data.push(path[i+1].0);
line_data.push(path[i+1].1);
line_data.push(normalx);
line_data.push(normaly);
}
gl::UseProgram(line_program);
gl::BindVertexArray(line_vao);
gl::BindBuffer(gl::ARRAY_BUFFER, line_vbo);
gl::BufferSubData(gl::ARRAY_BUFFER, 0, (path_edges*STRIDE*mem::size_of::<GLfloat>()) as GLsizeiptr as isize, mem::transmute(&line_data[0]));
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::BindVertexArray(0);
gl::UseProgram(0);
}
}
#[cfg(test)]
mod tests {
extern crate sdl2;
use self::sdl2::video::{GLProfile};
use self::sdl2::rect::Rect;
use self::sdl2::event::{Event};
use std::os::raw::c_void;
use super::*;
#[test]
fn it_works() {
let sdl = sdl2::init().unwrap();
let video_subsystem = sdl.video().unwrap();
let gl_attr = video_subsystem.gl_attr();
gl_attr.set_context_flags().debug().set();
gl_attr.set_context_version(3, 3);
gl_attr.set_context_profile(GLProfile::Core);
gl_attr.set_multisample_buffers(1);
gl_attr.set_multisample_samples(4);
gl_attr.set_double_buffer(true);
gl_attr.set_depth_size(24);
let window_bounds = Rect::new(100, 100, 500, 500);
let mut window = video_subsystem.window(
"glhelper test",
window_bounds.width(),
window_bounds.height())
.position(
window_bounds.x(),
window_bounds.y())
.opengl().build().unwrap();
let context = match window.gl_create_context() {
Ok(res) => res,
Err(..) => panic!("Could not open vert shader")
};
match window.gl_make_current(&context) {
Ok(_) => {},
Err(..) => panic!("setting current context")
}
gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const c_void);
let mut shaders: Vec<GLuint> = vec![];
let vsrc = include_str!("../shaders/line.vert.glsl");
let fsrc = include_str!("../shaders/line.frag.glsl");
let line_program = load_program(
vsrc,
fsrc,
&mut shaders);
}
}