-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathshader.rs
190 lines (173 loc) · 8.15 KB
/
shader.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#![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(vertexPath: &str, fragmentPath: &str) -> Shader {
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 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();
// 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
}
/// 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<f32>) {
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<f32>) {
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
}
}