| 13 | 13 |
use std::marker::PhantomData;
|
| 14 | 14 |
use std::os::raw::c_void;
|
| 15 | 15 |
|
| 16 | |
//
|
| 17 | |
|
| 16 |
/// Clear the screen to a generic color
|
| 18 | 17 |
pub fn clear() {
|
| 19 | 18 |
unsafe {
|
| 20 | 19 |
gl::ClearColor(0.3, 0.3, 0.3, 1.0);
|
|
| 22 | 21 |
}
|
| 23 | 22 |
}
|
| 24 | 23 |
|
| 24 |
/// Abstract over an OpenGL context as well as a basic event loop
|
| 25 | 25 |
pub struct Window {
|
| 26 | 26 |
events: glutin::EventsLoop,
|
| 27 | 27 |
gl_window: glutin::GlWindow,
|
| 28 | 28 |
}
|
| 29 | 29 |
|
| 30 | 30 |
impl Window {
|
| 31 |
/// Attempt to create a new window, and load all the relevant
|
| 32 |
/// OpenGL symbols in the process
|
| 31 | 33 |
pub fn create() -> Result<Window, Error> {
|
| 32 | 34 |
use glutin::GlContext;
|
| 33 | 35 |
let events = glutin::EventsLoop::new();
|
|
| 42 | 44 |
Ok(Window { events, gl_window })
|
| 43 | 45 |
}
|
| 44 | 46 |
|
| 47 |
/// Run the main event loop, calling the supplied callback with
|
| 48 |
/// every event
|
| 45 | 49 |
pub fn run<F>(self, mut cb: F) -> Result<(), Error>
|
| 46 | 50 |
where F: FnMut(glutin::Event) -> glutin::ControlFlow
|
| 47 | 51 |
{
|
|
| 66 | 70 |
|
| 67 | 71 |
}
|
| 68 | 72 |
|
| 73 |
/// Wrap an OpenGL shader. This will automatically be cleaned up from
|
| 74 |
/// the OpenGL state machine when it is dropped.
|
| 69 | 75 |
pub struct Shader {
|
| 70 | 76 |
pub n: gl::GLuint,
|
| 71 | 77 |
}
|
|
| 76 | 82 |
}
|
| 77 | 83 |
}
|
| 78 | 84 |
|
| 85 |
/// Right now, we're only concerned with either Fragment or Vertex
|
| 86 |
/// shaders. We might eventually want Geometry shaders, as well.
|
| 79 | 87 |
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
| 80 | 88 |
pub enum ShaderType {
|
| 81 | 89 |
Fragment,
|
|
| 83 | 91 |
}
|
| 84 | 92 |
|
| 85 | 93 |
impl ShaderType {
|
| 94 |
/// Convert a ShaderType value to OpenGL's enum value for the same
|
| 86 | 95 |
fn to_glenum(&self) -> gl::GLenum {
|
| 87 | 96 |
match *self {
|
| 88 | 97 |
ShaderType::Fragment => gl::FRAGMENT_SHADER,
|
|
| 92 | 101 |
}
|
| 93 | 102 |
|
| 94 | 103 |
impl Shader {
|
| 104 |
/// Compile a shade string and provide our Rust-level handle to it
|
| 95 | 105 |
pub fn compile(ty: ShaderType, src: &str) -> Result<Shader, Error> {
|
| 106 |
// this structure is gonna repeat a few times but also can't
|
| 107 |
// really get abstracted over in a clean way, so this comment
|
| 108 |
// could be consulted for the other functions, too.
|
| 96 | 109 |
let shader;
|
| 97 | 110 |
unsafe {
|
| 111 |
// we start by getting a new shader from OpenGL
|
| 98 | 112 |
shader = gl::CreateShader(ty.to_glenum());
|
| 113 |
// and also get the C string version of the source code
|
| 99 | 114 |
let c_str = ffi::CString::new(src.as_bytes())?;
|
| 115 |
|
| 116 |
// and then we compile it!
|
| 100 | 117 |
gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
|
| 101 | 118 |
gl::CompileShader(shader);
|
| 102 | 119 |
|
| 120 |
// this is the common part: we now ask OpenGL for the
|
| 121 |
// status of that compile, which OpenGL gives us by
|
| 122 |
// updating a pointer
|
| 103 | 123 |
let mut status = gl::FALSE as gl::GLint;
|
| 104 | 124 |
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
|
| 105 | 125 |
|
| 126 |
// If it's not good...
|
| 106 | 127 |
if status != (gl::TRUE as gl::GLint) {
|
| 128 |
// then then need to get the length of the error
|
| 129 |
// message, which, again we fetch via pointer
|
| 107 | 130 |
let mut len = 0;
|
| 108 | 131 |
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
|
| 132 |
|
| 133 |
// create the buffer that's big enough for that
|
| 134 |
// message
|
| 109 | 135 |
let mut buf = Vec::with_capacity(len as usize);
|
| 110 | 136 |
buf.set_len((len as usize) - 1);
|
| 137 |
// and then fill it in via OpenGL's mechanisms
|
| 111 | 138 |
gl::GetShaderInfoLog(
|
| 112 | 139 |
shader,
|
| 113 | 140 |
len,
|
| 114 | 141 |
ptr::null_mut(),
|
| 115 | 142 |
buf.as_mut_ptr() as *mut gl::GLchar
|
| 116 | 143 |
);
|
| 144 |
// and finally return it!
|
| 117 | 145 |
return Err(Error::CompileError(String::from_utf8(buf)?));
|
| 118 | 146 |
}
|
| 119 | 147 |
}
|
| 148 |
|
| 120 | 149 |
Ok(Shader { n: shader })
|
| 121 | 150 |
}
|
| 122 | 151 |
}
|
|
| 124 | 153 |
|
| 125 | 154 |
//
|
| 126 | 155 |
|
| 156 |
/// Represents a linked set of OpenGL shaders.
|
| 127 | 157 |
pub struct Program {
|
| 128 | 158 |
pub p: gl::GLuint,
|
| 129 | 159 |
pub shaders: Vec<Shader>,
|
|
| 139 | 169 |
}
|
| 140 | 170 |
|
| 141 | 171 |
impl Program {
|
| 172 |
/// Link several existing shaders into a single Program
|
| 142 | 173 |
pub fn link(shaders: Vec<Shader>) -> Result<Program, Error> {
|
| 174 |
// the stuff in here looks a lot like Shader::compile, so
|
| 175 |
// consult the inline docs for that to figure out what's going on
|
| 143 | 176 |
unsafe {
|
| 144 | 177 |
let program = gl::CreateProgram();
|
| 145 | 178 |
for s in shaders.iter() {
|