|
- use std::fs::File;
- use std::io::Read;
- use std::path::Path;
- use std::ptr::{null, null_mut};
- use std::str::from_utf8;
-
- use crate::{
- error::Error,
- matrix::Matrix4f,
- misc::{AsEnum, Bindable},
- };
-
- /* Programm */
-
- #[derive(Default)]
- pub struct Program {
- id: gl::GLuint,
- }
-
- impl Program {
- pub fn from_shaders<I>(iter: I) -> Result<Self, Error>
- where
- I: IntoIterator<Item = Shader>,
- {
- Self::from_shaders_result(iter.into_iter().map(Ok))
- }
-
- pub fn from_shaders_result<I, E>(iter: I) -> Result<Self, E>
- where
- I: IntoIterator<Item = Result<Shader, E>>,
- E: From<Error>,
- {
- let id = gl::create_program();
- let id = Error::err_if(&0, id)?;
-
- let shaders = iter.into_iter().collect::<Result<Vec<_>, _>>()?;
- for shader in &shaders {
- gl::attach_shader(id, shader.id());
- }
-
- gl::link_program(id);
-
- for shader in &shaders {
- gl::detach_shader(id, shader.id());
- }
-
- let mut success = 1;
- gl::get_program_iv(id, gl::LINK_STATUS, &mut success);
-
- if success != 1 {
- let mut len = 0;
- gl::get_program_iv(id, gl::INFO_LOG_LENGTH, &mut len);
-
- let mut buffer = Vec::<u8>::with_capacity(len as usize + 1);
- buffer.resize(len as usize, 0);
-
- gl::get_program_info_log(
- id,
- len,
- null_mut(),
- buffer.as_mut_ptr() as *mut gl::types::GLchar,
- );
-
- let msg = from_utf8(&buffer).map_err(Error::Utf8Error)?;
-
- return Err(Error::ShaderLink(msg.into()).into());
- }
-
- Ok(Program { id })
- }
-
- pub fn id(&self) -> gl::GLuint {
- self.id
- }
-
- pub fn uniform(&self, location: gl::GLint, uniform: Uniform<'_>) {
- match uniform {
- Uniform::Matrix4f(v) => gl::uniform_matrix_4fv(location, 1, gl::FALSE, v.as_ptr()),
- }
- }
- }
-
- impl Drop for Program {
- fn drop(&mut self) {
- gl::delete_program(self.id);
- }
- }
-
- impl Bindable for Program {
- fn bind(&self) {
- gl::use_program(self.id);
- }
-
- fn unbind(&self) {
- gl::use_program(0);
- }
- }
-
- /* Shader */
-
- pub struct Shader {
- id: gl::GLuint,
- }
-
- impl Shader {
- pub fn from_string(type_: Type, mut source: String) -> Result<Self, Error> {
- let id = gl::create_shader(type_.as_enum());
- let id = Error::err_if(&0, id)?;
-
- source.push('\0');
- let source_ptr = source.as_ptr() as *const i8;
- let source_ptr: *const *const i8 = &source_ptr;
-
- gl::shader_source(id, 1, source_ptr, null());
- gl::compile_shader(id);
-
- let mut success = 1;
- gl::get_shader_iv(id, gl::COMPILE_STATUS, &mut success);
-
- if success != 1 {
- let mut len = 0;
- gl::get_shader_iv(id, gl::INFO_LOG_LENGTH, &mut len);
-
- let mut buffer = Vec::<u8>::with_capacity(len as usize + 1);
- buffer.resize(len as usize, 0);
-
- gl::get_shader_info_log(
- id,
- len,
- null_mut(),
- buffer.as_mut_ptr() as *mut gl::types::GLchar,
- );
-
- let msg = from_utf8(&buffer)?;
-
- return Err(Error::ShaderCompile {
- code: source,
- error: msg.into(),
- });
- }
-
- Ok(Self { id })
- }
-
- pub fn from_reader<R>(type_: Type, reader: &mut R) -> Result<Self, Error>
- where
- R: Read,
- {
- let mut source = String::new();
- reader.read_to_string(&mut source)?;
-
- Self::from_string(type_, source)
- }
-
- pub fn from_file<P>(type_: Type, path: P) -> Result<Self, Error>
- where
- P: AsRef<Path>,
- {
- let mut file = File::open(&path)?;
-
- match Self::from_reader(type_, &mut file) {
- Ok(v) => Ok(v),
- Err(Error::ShaderCompile { code, error }) => Err(Error::ShaderCompile {
- code: format!("{}\n{}", path.as_ref().display(), code),
- error,
- }),
- Err(err) => Err(err),
- }
- }
-
- pub fn id(&self) -> gl::GLuint {
- self.id
- }
- }
-
- impl Drop for Shader {
- fn drop(&mut self) {
- gl::delete_shader(self.id);
- }
- }
-
- /* Type */
-
- #[derive(Debug, Copy, Clone, Eq, PartialEq)]
- pub enum Type {
- Vertex,
- Compute,
- Fragment,
- Geometry,
- TesslationControl,
- TesslationEvaluation,
- }
-
- impl AsEnum for Type {
- fn as_enum(&self) -> gl::GLenum {
- match self {
- Self::Vertex => gl::VERTEX_SHADER,
- Self::Compute => gl::COMPUTE_SHADER,
- Self::Fragment => gl::FRAGMENT_SHADER,
- Self::Geometry => gl::GEOMETRY_SHADER,
- Self::TesslationControl => gl::TESS_CONTROL_SHADER,
- Self::TesslationEvaluation => gl::TESS_EVALUATION_SHADER,
- }
- }
- }
-
- /* Uniform */
-
- pub enum Uniform<'a> {
- Matrix4f(&'a Matrix4f),
- }
|