use gl;
use gl::types::*;
use nalgebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4};
use std;
use std::ffi::CString;
use std::fs::File;
use std::io;
use std::io::Read;
use std::ptr;
lazy_static! {
pub static ref DEFAULT_SHADER: Shader = Shader::default();
}
lazy_static! {
pub static ref SPRITE_SHADER: Shader = {
let (vert, frag, id);
unsafe {
let (v, f, i) = Shader::do_shader(
&CString::new(SPRITE_VS.as_bytes()).unwrap(),
&CString::new(SPRITE_FS.as_bytes()).unwrap(),
)
.unwrap();
frag = f;
vert = v;
id = i;
}
Shader { id, frag, vert }
};
}
lazy_static! {
pub static ref BATCH_SHADER: Shader = {
let (vert, frag, id);
unsafe {
let (v, f, i) = Shader::do_shader(
&CString::new(BATCH_VS.as_bytes()).unwrap(),
&CString::new(FS.as_bytes()).unwrap(),
)
.unwrap();
vert = v;
frag = f;
id = i;
}
Shader {
id: id,
frag: frag,
vert: vert,
}
};
}
lazy_static! {
pub static ref NO_TEXTURE_SHADER: Shader = {
let (vert, frag, id);
unsafe {
let (v, f, i) = Shader::do_shader(
&CString::new(VS.as_bytes()).unwrap(),
&CString::new(NO_TEXTURE_FS.as_bytes()).unwrap(),
)
.unwrap();
vert = v;
frag = f;
id = i;
}
Shader {
id: id,
frag: frag,
vert: vert,
}
};
}
#[derive(Debug)]
pub struct Shader {
id: u32,
vert: u32,
frag: u32,
}
static SPRITE_VS: &'static str = "#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 2) in vec3 aColor;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 transform;
uniform mat4 model;
uniform mat4 projection;
void main()
{
gl_Position = projection * transform * vec4(aPos.xy, 0.0, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}";
static SPRITE_FS: &'static str = "#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;
void main()
{
FragColor = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);
}";
static BATCH_VS: &'static str = "#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 2) in vec3 aColor;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 glob_model;
uniform mat4 projection;
void main()
{
gl_Position = projection * glob_model * vec4(aPos.xy, 0.0, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
";
static VS: &'static str = "#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 2) in vec3 aColor;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 transform;
uniform mat4 projection;
void main()
{
gl_Position = projection * transform * vec4(aPos.xy, 0.0, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}";
static FS: &'static str = "#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;
void main()
{
FragColor = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);
}";
static NO_TEXTURE_FS: &'static str = "#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0);
}";
pub fn file_to_cstring(name: &str) -> Result<CString, io::Error> {
let mut content = String::new();
File::open(name)?.read_to_string(&mut content)?;
Ok(CString::new(content.as_bytes()).unwrap())
}
impl Shader {
pub fn new(vert: &str, frag: &str) -> Result<Shader, io::Error> {
let vert_source = file_to_cstring(vert)?;
let frag_source = file_to_cstring(frag)?;
let (vert_id, frag_id, id);
unsafe {
let (v, f, i) = Shader::do_shader(&vert_source, &frag_source)?;
vert_id = v;
frag_id = f;
id = i;
}
Ok(Shader {
id,
frag: frag_id,
vert: vert_id,
})
}
unsafe fn do_shader(
vert_code: &CString,
frag_code: &CString,
) -> Result<(u32, u32, u32), io::Error> {
let id = gl::CreateProgram();
let vert_id = Shader::compile_shader(&vert_code, gl::VERTEX_SHADER);
let frag_id = Shader::compile_shader(&frag_code, gl::FRAGMENT_SHADER);
gl::AttachShader(id, vert_id);
gl::AttachShader(id, frag_id);
gl::LinkProgram(id);
let mut status: i32 = 0;
let s: String = std::iter::repeat(' ').take(512).collect();
let info_log: CString = CString::new(s.as_bytes()).unwrap();
gl::GetProgramiv(id, gl::LINK_STATUS, &mut status);
if status == 0 {
gl::GetProgramInfoLog(id, 512, ptr::null_mut(), info_log.as_ptr() as *mut _);
println!("Could not link shaders {}", info_log.into_string().unwrap());
}
gl::DeleteShader(vert_id);
gl::DeleteShader(frag_id);
Ok((vert_id, frag_id, id))
}
unsafe fn compile_shader(code: &CString, gl_type: GLenum) -> u32 {
let id = gl::CreateShader(gl_type);
gl::ShaderSource(id, 1, &code.as_ptr(), ptr::null());
gl::CompileShader(id);
let mut success: i32 = 0;
let s: String = std::iter::repeat(' ').take(512).collect();
let info_log: CString = CString::new(s.as_bytes()).unwrap();
gl::GetShaderiv(id, gl::COMPILE_STATUS, &mut success);
if success == 0 {
gl::GetShaderInfoLog(id, 512, ptr::null_mut(), info_log.as_ptr() as *mut _);
println!(
"Could not compile shaders {}",
info_log.into_string().unwrap()
);
};
id
}
pub fn activate(&self) {
unsafe {
gl::UseProgram(self.id);
}
}
pub fn uniform_f4(&mut self, name: &str, value: Vector4<f32>) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::Uniform4f(pos, value.x, value.y, value.z, value.w);
}
}
pub fn uniform_f3(&mut self, name: &str, value: Vector3<f32>) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::Uniform3f(pos, value.x, value.y, value.z);
}
}
pub fn uniform_f2(&mut self, name: &str, value: Vector2<f32>) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::Uniform2f(pos, value.x, value.y);
}
}
pub fn uniform_f(&mut self, name: &str, value: f32) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::Uniform1f(pos, value);
}
}
pub fn uniform_bool(&mut self, name: &str, value: bool) {
self.uniform_int(name, value as i32);
}
pub fn uniform_int(&mut self, name: &str, value: i32) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::Uniform1i(pos, value);
}
}
pub fn uniform_int2(&mut self, name: &str, value: Vector2<i32>) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::Uniform2i(pos, value.x, value.y);
}
}
pub fn uniform_int3(&mut self, name: &str, value: Vector3<i32>) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::Uniform3i(pos, value.x, value.y, value.z);
}
}
pub fn uniform_int4(&mut self, name: &str, value: Vector4<i32>) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::Uniform4i(pos, value.x, value.y, value.z, value.w);
}
}
pub fn uniform_mat4f(&self, name: &str, value: &Matrix4<f32>) {
unsafe {
let string = CString::new(name.as_bytes()).unwrap();
let pos = gl::GetUniformLocation(self.id, string.as_ptr());
gl::UniformMatrix4fv(pos, 1, gl::FALSE, value.as_slice().as_ptr());
}
}
pub fn uniform_mat3f(&mut self, name: &str, value: Matrix3<f32>) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::UniformMatrix3fv(pos, 1, gl::FALSE, value.as_slice().as_ptr());
}
}
pub fn uniform_mat2f(&mut self, name: &str, value: Matrix2<f32>) {
unsafe {
let pos = gl::GetUniformLocation(self.id, name.as_ptr() as *const _);
gl::UniformMatrix2fv(pos, 1, gl::FALSE, value.as_slice().as_ptr());
}
}
}
impl Default for Shader {
fn default() -> Shader {
let vert_source = CString::new(VS.as_bytes()).unwrap();
let frag_source = CString::new(FS.as_bytes()).unwrap();
let (vert_id, frag_id, id);
unsafe {
let (v, f, i) = Shader::do_shader(&vert_source, &frag_source).unwrap();
vert_id = v;
frag_id = f;
id = i;
}
Shader {
id,
frag: frag_id,
vert: vert_id,
}
}
}
impl Drop for Shader {
fn drop(&mut self) {
unsafe {
gl::DeleteShader(self.vert);
gl::DeleteShader(self.frag);
gl::DeleteProgram(self.id);
}
println!("Shaders {} deleted.", self.id);
}
}