From 4b606801ae6c5e7f95e9ff8a38b3d51d035044b1 Mon Sep 17 00:00:00 2001 From: Piotr Date: Tue, 18 Aug 2020 18:20:22 +0200 Subject: [PATCH] Shader --- Cargo.lock | 200 +------------------------------------------------- Cargo.toml | 4 +- src/main.rs | 105 +++++++++++--------------- src/shader.rs | 196 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 262 deletions(-) create mode 100644 src/shader.rs diff --git a/Cargo.lock b/Cargo.lock index 0d94ecd..3736b50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,20 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "addr2line" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" - [[package]] name = "adler32" version = "1.2.0" @@ -33,20 +18,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -[[package]] -name = "backtrace" -version = "0.3.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - [[package]] name = "bitflags" version = "1.2.1" @@ -82,15 +53,6 @@ dependencies = [ "rand", ] -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - [[package]] name = "cmake" version = "0.1.44" @@ -172,8 +134,6 @@ dependencies = [ "gl", "glfw", "image", - "imgui", - "imgui-glium-renderer", ] [[package]] @@ -191,12 +151,6 @@ dependencies = [ "num-traits 0.1.43", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -213,19 +167,13 @@ dependencies = [ "lzw", ] -[[package]] -name = "gimli" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" - [[package]] name = "gl" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81457bb802910ad5b535eb48541c51830a761804aa5b7087adbc9d049aa57aca" dependencies = [ - "gl_generator 0.9.0", + "gl_generator", ] [[package]] @@ -234,20 +182,9 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a" dependencies = [ - "khronos_api 2.2.0", + "khronos_api", "log", - "xml-rs 0.7.0", -] - -[[package]] -name = "gl_generator" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" -dependencies = [ - "khronos_api 3.1.0", - "log", - "xml-rs 0.8.3", + "xml-rs", ] [[package]] @@ -274,21 +211,6 @@ dependencies = [ "cmake", ] -[[package]] -name = "glium" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030bb23a12fac7e589b002c5e131e89348df88f91b56e3f3dbc4249527eeebf9" -dependencies = [ - "backtrace", - "fnv", - "gl_generator 0.14.0", - "lazy_static", - "memoffset", - "smallvec", - "takeable-option", -] - [[package]] name = "hermit-abi" version = "0.1.15" @@ -316,38 +238,6 @@ dependencies = [ "scoped_threadpool", ] -[[package]] -name = "imgui" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fdb2bcc7e498e78137ce28705ae836d69e36ee2eac89d0d926cfabfcf550570" -dependencies = [ - "bitflags", - "glium", - "imgui-sys", - "lazy_static", - "parking_lot", -] - -[[package]] -name = "imgui-glium-renderer" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c73e47cb3db3e354e3977265b14d7e6ff8b55a83f06ab6c7d04b4d441d64f586" -dependencies = [ - "glium", - "imgui", -] - -[[package]] -name = "imgui-sys" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72be9671d64dd0ed26bb708cd10060a431262ac90ae70cf7c5912feefe6849da" -dependencies = [ - "cc", -] - [[package]] name = "inflate" version = "0.4.5" @@ -373,12 +263,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554" -[[package]] -name = "khronos_api" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" - [[package]] name = "lazy_static" version = "1.4.0" @@ -391,15 +275,6 @@ version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" -[[package]] -name = "lock_api" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.11" @@ -430,15 +305,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "miniz_oxide" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" -dependencies = [ - "adler", -] - [[package]] name = "nom" version = "1.2.4" @@ -553,36 +419,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" - -[[package]] -name = "parking_lot" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" -dependencies = [ - "cfg-if", - "cloudabi", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - [[package]] name = "png" version = "0.12.0" @@ -675,18 +511,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "rustc-demangle" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" - [[package]] name = "rustc-serialize" version = "0.3.24" @@ -714,12 +538,6 @@ dependencies = [ "nom", ] -[[package]] -name = "smallvec" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" - [[package]] name = "syn" version = "0.15.44" @@ -731,12 +549,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "takeable-option" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ae8932fcfea38b7d3883ae2ab357b0d57a02caaa18ebb4f5ece08beaec4aa0" - [[package]] name = "unicode-xid" version = "0.1.0" @@ -773,9 +585,3 @@ checksum = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" dependencies = [ "bitflags", ] - -[[package]] -name = "xml-rs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" diff --git a/Cargo.toml b/Cargo.toml index d04021c..831acbd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,4 @@ image = "0.19.0" # only needed from chapter 3 on # tobj = "0.1.6" # num = "0.2.0" -# rand = "0.5.5" -imgui = "0.4.0" -imgui-glium-renderer = "0.4.0" \ No newline at end of file +# rand = "0.5.5" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 83c7440..4982992 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ use std::mem; use std::os::raw::c_void; mod consts; +mod shader; pub fn main() { // glfw: initialize and configure @@ -36,92 +37,72 @@ pub fn main() { gl::load_with(|symbol| window.get_proc_address(symbol) as *const _); - let (shaderProgram, VAO) = unsafe { - let vertexShader = gl::CreateShader(gl::VERTEX_SHADER); - let c_str_vertex = CString::new(consts::VERTEX_SHADER_SRC.as_bytes()).unwrap(); - gl::ShaderSource(vertexShader, 1, &c_str_vertex.as_ptr(), ptr::null()); - gl::CompileShader(vertexShader); - - - // check for shader compile errors - let mut success = gl::FALSE as GLint; - let mut infoLog = Vec::with_capacity(512); - infoLog.set_len(512 - 1); // subtract 1 to skip the trailing null character - gl::GetShaderiv(vertexShader, gl::COMPILE_STATUS, &mut success); - if success != gl::TRUE as GLint { - gl::GetShaderInfoLog(vertexShader, 512, ptr::null_mut(), infoLog.as_mut_ptr() as *mut GLchar); - println!("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n{}", str::from_utf8(&infoLog).unwrap()); - } - - let fragmentShader = gl::CreateShader(gl::FRAGMENT_SHADER); - let c_str_fragment = CString::new(consts::FRAGMENT_SHADER_SRC.as_bytes()).unwrap(); - gl::ShaderSource(fragmentShader,1, &c_str_fragment.as_ptr(), ptr::null()); - gl::CompileShader(fragmentShader); - - - // check for shader compile errors - gl::GetShaderiv(fragmentShader, gl::COMPILE_STATUS, &mut success); - if success != gl::TRUE as GLint { - gl::GetShaderInfoLog(fragmentShader, 512, ptr::null_mut(), infoLog.as_mut_ptr() as *mut GLchar); - println!("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n{}", str::from_utf8(&infoLog).unwrap()); - } - - let shaderProgram = gl::CreateProgram(); - gl::AttachShader(shaderProgram, vertexShader); - gl::AttachShader(shaderProgram, fragmentShader); - gl::LinkProgram(shaderProgram); - - // check for linking errors - gl::GetProgramiv(shaderProgram, gl::LINK_STATUS, &mut success); - if success != gl::TRUE as GLint { - gl::GetProgramInfoLog(shaderProgram, 512, ptr::null_mut(), infoLog.as_mut_ptr() as *mut GLchar); - println!("ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n{}", str::from_utf8(&infoLog).unwrap()); - } - gl::DeleteShader(vertexShader); - gl::DeleteShader(fragmentShader); - + let (shaderObject, VAO) = unsafe { + let vShaderCode = CString::new(consts::VERTEX_SHADER_SRC.as_bytes()).unwrap(); + let fShaderCode = CString::new(consts::FRAGMENT_SHADER_SRC.as_bytes()).unwrap(); + let shader = crate::shader::Shader::new(vShaderCode, fShaderCode); // set up vertex data (and buffer(s)) and configure vertex attributes // ------------------------------------------------------------------ // HINT: type annotation is crucial since default for float literals is f64 - let vertices: [f32; 9] = [ - -0.5, -0.5, 0.0, // left - 0.5, -0.5, 0.0, // right - 0.0, 0.5, 0.0 // top + let vertices: [f32; 12] = [ + 0.5, 0.5, 0.0, // top right + 0.5, -0.5, 0.0, // bottom right + -0.5, -0.5, 0.0, // bottom left + -0.5, 0.5, 0.0 // top left ]; - let (mut VBO, mut VAO) = (0, 0); + let indices = [ // note that we start from 0! + 0, 1, 3, // first Triangle + 1, 2, 3 // second Triangle + ]; + + let (mut VBO, mut VAO, mut EBO) = (0, 0, 0); gl::GenVertexArrays(1, &mut VAO); gl::GenBuffers(1, &mut VBO); + gl::GenBuffers(1, &mut EBO); + // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). gl::BindVertexArray(VAO); gl::BindBuffer(gl::ARRAY_BUFFER, VBO); gl::BufferData(gl::ARRAY_BUFFER, - (vertices.len() * mem::size_of::()) as GLsizeiptr, - &vertices[0] as *const f32 as *const c_void, - gl::STATIC_DRAW); + (vertices.len() * mem::size_of::()) as GLsizeiptr, + &vertices[0] as *const f32 as *const c_void, + gl::STATIC_DRAW); - gl::VertexAttribPointer(0,3,gl::FLOAT, gl::FALSE, 3 * mem::size_of::() as GLsizei, ptr::null()); + gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, EBO); + gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, + (indices.len() * mem::size_of::()) as GLsizeiptr, + &indices[0] as *const i32 as *const c_void, + gl::STATIC_DRAW); + + gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, 3 * mem::size_of::() as GLsizei, ptr::null()); gl::EnableVertexAttribArray(0); + + // note that this is allowed, the call to gl::VertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind gl::BindBuffer(gl::ARRAY_BUFFER, 0); + // remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound. + // gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0); + + // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other + // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary. + gl::BindVertexArray(0); + // uncomment this call to draw in wireframe polygons. // gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE); - (shaderProgram, VAO) + (shader, VAO) }; // render loop // ----------- - let mut color_r = 0.0; - let mut color_g = 0.0; - let mut color_b = 0.0; + let color_r = 0.3; + let color_g = 0.3; + let color_b = 0.6; while !window.should_close() { // events // ----- process_events(&mut window, &events); - color_r = (color_r + 0.03) % 1.0; - color_g = (color_g + 0.01) % 0.6; - color_b = (color_b + 0.02) % 1.0; // render // ------ unsafe { @@ -129,9 +110,9 @@ pub fn main() { gl::Clear(gl::COLOR_BUFFER_BIT); // draw our first triangle - gl::UseProgram(shaderProgram); + shaderObject.useProgram(); gl::BindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized - gl::DrawArrays(gl::TRIANGLES, 0, 3); + gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null()); } // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) diff --git a/src/shader.rs b/src/shader.rs new file mode 100644 index 0000000..3fd2005 --- /dev/null +++ b/src/shader.rs @@ -0,0 +1,196 @@ +#![allow(non_snake_case)] +use std::ffi::{CString, CStr}; +use std::fs::File; +use std::io::Read; +use std::ptr; +use std::str; + +use gl; +use gl::types::*; + +use cgmath::{Matrix, Matrix4, Vector3}; +use cgmath::prelude::*; + +pub struct Shader { + pub ID: u32, +} + +/// NOTE: mixture of `shader_s.h` and `shader_m.h` (the latter just contains +/// a few more setters for uniforms) +#[allow(dead_code)] +impl Shader { + + pub fn new(vShaderCode: CString, fShaderCode: CString) -> Shader { + let mut shader = Shader { ID: 0 }; + + // 2. compile shaders + unsafe { + // vertex shader + let vertex = gl::CreateShader(gl::VERTEX_SHADER); + gl::ShaderSource(vertex, 1, &vShaderCode.as_ptr(), ptr::null()); + gl::CompileShader(vertex); + shader.checkCompileErrors(vertex, "VERTEX"); + // fragment Shader + let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); + gl::ShaderSource(fragment, 1, &fShaderCode.as_ptr(), ptr::null()); + gl::CompileShader(fragment); + shader.checkCompileErrors(fragment, "FRAGMENT"); + // shader Program + let ID = gl::CreateProgram(); + gl::AttachShader(ID, vertex); + gl::AttachShader(ID, fragment); + gl::LinkProgram(ID); + shader.checkCompileErrors(ID, "PROGRAM"); + // delete the shaders as they're linked into our program now and no longer necessary + gl::DeleteShader(vertex); + gl::DeleteShader(fragment); + shader.ID = ID; + } + + shader + } + + pub fn from_file(vertexPath: &str, fragmentPath: &str) -> Shader { + // 1. retrieve the vertex/fragment source code from filesystem + let mut vShaderFile = File::open(vertexPath) + .unwrap_or_else(|_| panic!("Failed to open {}", vertexPath)); + let mut fShaderFile = File::open(fragmentPath) + .unwrap_or_else(|_| panic!("Failed to open {}", fragmentPath)); + let mut vertexCode = String::new(); + let mut fragmentCode = String::new(); + vShaderFile + .read_to_string(&mut vertexCode) + .expect("Failed to read vertex shader"); + fShaderFile + .read_to_string(&mut fragmentCode) + .expect("Failed to read fragment shader"); + + let vShaderCode = CString::new(vertexCode.as_bytes()).unwrap(); + let fShaderCode = CString::new(fragmentCode.as_bytes()).unwrap(); + + Shader::new(vShaderCode, fShaderCode) + } + + /// activate the shader + /// ------------------------------------------------------------------------ + pub unsafe fn useProgram(&self) { + gl::UseProgram(self.ID) + } + + /// utility uniform functions + /// ------------------------------------------------------------------------ + pub unsafe fn setBool(&self, name: &CStr, value: bool) { + gl::Uniform1i(gl::GetUniformLocation(self.ID, name.as_ptr()), value as i32); + } + /// ------------------------------------------------------------------------ + pub unsafe fn setInt(&self, name: &CStr, value: i32) { + gl::Uniform1i(gl::GetUniformLocation(self.ID, name.as_ptr()), value); + } + /// ------------------------------------------------------------------------ + pub unsafe fn setFloat(&self, name: &CStr, value: f32) { + gl::Uniform1f(gl::GetUniformLocation(self.ID, name.as_ptr()), value); + } + /// ------------------------------------------------------------------------ + pub unsafe fn setVector3(&self, name: &CStr, value: &Vector3) { + gl::Uniform3fv(gl::GetUniformLocation(self.ID, name.as_ptr()), 1, value.as_ptr()); + } + /// ------------------------------------------------------------------------ + pub unsafe fn setVec3(&self, name: &CStr, x: f32, y: f32, z: f32) { + gl::Uniform3f(gl::GetUniformLocation(self.ID, name.as_ptr()), x, y, z); + } + /// ------------------------------------------------------------------------ + pub unsafe fn setMat4(&self, name: &CStr, mat: &Matrix4) { + gl::UniformMatrix4fv(gl::GetUniformLocation(self.ID, name.as_ptr()), 1, gl::FALSE, mat.as_ptr()); + } + + /// utility function for checking shader compilation/linking errors. + /// ------------------------------------------------------------------------ + unsafe fn checkCompileErrors(&self, shader: u32, type_: &str) { + let mut success = gl::FALSE as GLint; + let mut infoLog = Vec::with_capacity(1024); + infoLog.set_len(1024 - 1); // subtract 1 to skip the trailing null character + if type_ != "PROGRAM" { + gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success); + if success != gl::TRUE as GLint { + gl::GetShaderInfoLog(shader, 1024, ptr::null_mut(), infoLog.as_mut_ptr() as *mut GLchar); + println!("ERROR::SHADER_COMPILATION_ERROR of type: {}\n{}\n \ + -- --------------------------------------------------- -- ", + type_, + str::from_utf8(&infoLog).unwrap()); + } + + } else { + gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success); + if success != gl::TRUE as GLint { + gl::GetProgramInfoLog(shader, 1024, ptr::null_mut(), infoLog.as_mut_ptr() as *mut GLchar); + println!("ERROR::PROGRAM_LINKING_ERROR of type: {}\n{}\n \ + -- --------------------------------------------------- -- ", + type_, + str::from_utf8(&infoLog).unwrap()); + } + } + + } + + /// Only used in 4.9 Geometry shaders - ignore until then (shader.h in original C++) + pub fn with_geometry_shader(vertexPath: &str, fragmentPath: &str, geometryPath: &str) -> Self { + let mut shader = Shader { ID: 0 }; + // 1. retrieve the vertex/fragment source code from filesystem + let mut vShaderFile = File::open(vertexPath) + .unwrap_or_else(|_| panic!("Failed to open {}", vertexPath)); + let mut fShaderFile = File::open(fragmentPath) + .unwrap_or_else(|_| panic!("Failed to open {}", fragmentPath)); + let mut gShaderFile = File::open(geometryPath) + .unwrap_or_else(|_| panic!("Failed to open {}", geometryPath)); + let mut vertexCode = String::new(); + let mut fragmentCode = String::new(); + let mut geometryCode = String::new(); + vShaderFile + .read_to_string(&mut vertexCode) + .expect("Failed to read vertex shader"); + fShaderFile + .read_to_string(&mut fragmentCode) + .expect("Failed to read fragment shader"); + gShaderFile + .read_to_string(&mut geometryCode) + .expect("Failed to read geometry shader"); + + let vShaderCode = CString::new(vertexCode.as_bytes()).unwrap(); + let fShaderCode = CString::new(fragmentCode.as_bytes()).unwrap(); + let gShaderCode = CString::new(geometryCode.as_bytes()).unwrap(); + + // 2. compile shaders + unsafe { + // vertex shader + let vertex = gl::CreateShader(gl::VERTEX_SHADER); + gl::ShaderSource(vertex, 1, &vShaderCode.as_ptr(), ptr::null()); + gl::CompileShader(vertex); + shader.checkCompileErrors(vertex, "VERTEX"); + // fragment Shader + let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); + gl::ShaderSource(fragment, 1, &fShaderCode.as_ptr(), ptr::null()); + gl::CompileShader(fragment); + shader.checkCompileErrors(fragment, "FRAGMENT"); + // geometry shader + let geometry = gl::CreateShader(gl::GEOMETRY_SHADER); + gl::ShaderSource(geometry, 1, &gShaderCode.as_ptr(), ptr::null()); + gl::CompileShader(geometry); + shader.checkCompileErrors(geometry, "GEOMETRY"); + + // shader Program + let ID = gl::CreateProgram(); + gl::AttachShader(ID, vertex); + gl::AttachShader(ID, fragment); + gl::AttachShader(ID, geometry); + gl::LinkProgram(ID); + shader.checkCompileErrors(ID, "PROGRAM"); + // delete the shaders as they're linked into our program now and no longer necessary + gl::DeleteShader(vertex); + gl::DeleteShader(fragment); + gl::DeleteShader(geometry); + shader.ID = ID; + } + + shader + } +}