Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

212 lignes
4.9 KiB

  1. use std::fs::File;
  2. use std::io::Read;
  3. use std::path::Path;
  4. use std::ptr::{null, null_mut};
  5. use std::str::from_utf8;
  6. use crate::{
  7. error::Error,
  8. matrix::Matrix4f,
  9. misc::{AsEnum, Bindable},
  10. };
  11. /* Programm */
  12. #[derive(Default)]
  13. pub struct Program {
  14. id: gl::GLuint,
  15. }
  16. impl Program {
  17. pub fn from_shaders<I>(iter: I) -> Result<Self, Error>
  18. where
  19. I: IntoIterator<Item = Shader>,
  20. {
  21. Self::from_shaders_result(iter.into_iter().map(Ok))
  22. }
  23. pub fn from_shaders_result<I, E>(iter: I) -> Result<Self, E>
  24. where
  25. I: IntoIterator<Item = Result<Shader, E>>,
  26. E: From<Error>,
  27. {
  28. let id = gl::create_program();
  29. let id = Error::err_if(&0, id)?;
  30. let shaders = iter.into_iter().collect::<Result<Vec<_>, _>>()?;
  31. for shader in &shaders {
  32. gl::attach_shader(id, shader.id());
  33. }
  34. gl::link_program(id);
  35. for shader in &shaders {
  36. gl::detach_shader(id, shader.id());
  37. }
  38. let mut success = 1;
  39. gl::get_program_iv(id, gl::LINK_STATUS, &mut success);
  40. if success != 1 {
  41. let mut len = 0;
  42. gl::get_program_iv(id, gl::INFO_LOG_LENGTH, &mut len);
  43. let mut buffer = Vec::<u8>::with_capacity(len as usize + 1);
  44. buffer.resize(len as usize, 0);
  45. gl::get_program_info_log(
  46. id,
  47. len,
  48. null_mut(),
  49. buffer.as_mut_ptr() as *mut gl::types::GLchar,
  50. );
  51. let msg = from_utf8(&buffer).map_err(Error::Utf8Error)?;
  52. return Err(Error::ShaderLink(msg.into()).into());
  53. }
  54. Ok(Program { id })
  55. }
  56. pub fn id(&self) -> gl::GLuint {
  57. self.id
  58. }
  59. pub fn uniform(&self, location: gl::GLint, uniform: Uniform<'_>) {
  60. match uniform {
  61. Uniform::Matrix4f(v) => gl::uniform_matrix_4fv(location, 1, gl::FALSE, v.as_ptr()),
  62. }
  63. }
  64. }
  65. impl Drop for Program {
  66. fn drop(&mut self) {
  67. gl::delete_program(self.id);
  68. }
  69. }
  70. impl Bindable for Program {
  71. fn bind(&self) {
  72. gl::use_program(self.id);
  73. }
  74. fn unbind(&self) {
  75. gl::use_program(0);
  76. }
  77. }
  78. /* Shader */
  79. pub struct Shader {
  80. id: gl::GLuint,
  81. }
  82. impl Shader {
  83. pub fn from_string(type_: Type, mut source: String) -> Result<Self, Error> {
  84. let id = gl::create_shader(type_.as_enum());
  85. let id = Error::err_if(&0, id)?;
  86. source.push('\0');
  87. let source_ptr = source.as_ptr() as *const i8;
  88. let source_ptr: *const *const i8 = &source_ptr;
  89. gl::shader_source(id, 1, source_ptr, null());
  90. gl::compile_shader(id);
  91. let mut success = 1;
  92. gl::get_shader_iv(id, gl::COMPILE_STATUS, &mut success);
  93. if success != 1 {
  94. let mut len = 0;
  95. gl::get_shader_iv(id, gl::INFO_LOG_LENGTH, &mut len);
  96. let mut buffer = Vec::<u8>::with_capacity(len as usize + 1);
  97. buffer.resize(len as usize, 0);
  98. gl::get_shader_info_log(
  99. id,
  100. len,
  101. null_mut(),
  102. buffer.as_mut_ptr() as *mut gl::types::GLchar,
  103. );
  104. let msg = from_utf8(&buffer)?;
  105. return Err(Error::ShaderCompile {
  106. code: source,
  107. error: msg.into(),
  108. });
  109. }
  110. Ok(Self { id })
  111. }
  112. pub fn from_reader<R>(type_: Type, reader: &mut R) -> Result<Self, Error>
  113. where
  114. R: Read,
  115. {
  116. let mut source = String::new();
  117. reader.read_to_string(&mut source)?;
  118. Self::from_string(type_, source)
  119. }
  120. pub fn from_file<P>(type_: Type, path: P) -> Result<Self, Error>
  121. where
  122. P: AsRef<Path>,
  123. {
  124. let mut file = File::open(&path)?;
  125. match Self::from_reader(type_, &mut file) {
  126. Ok(v) => Ok(v),
  127. Err(Error::ShaderCompile { code, error }) => Err(Error::ShaderCompile {
  128. code: format!("{}\n{}", path.as_ref().display(), code),
  129. error,
  130. }),
  131. Err(err) => Err(err),
  132. }
  133. }
  134. pub fn id(&self) -> gl::GLuint {
  135. self.id
  136. }
  137. }
  138. impl Drop for Shader {
  139. fn drop(&mut self) {
  140. gl::delete_shader(self.id);
  141. }
  142. }
  143. /* Type */
  144. #[derive(Debug, Copy, Clone, Eq, PartialEq)]
  145. pub enum Type {
  146. Vertex,
  147. Compute,
  148. Fragment,
  149. Geometry,
  150. TesslationControl,
  151. TesslationEvaluation,
  152. }
  153. impl AsEnum for Type {
  154. fn as_enum(&self) -> gl::GLenum {
  155. match self {
  156. Self::Vertex => gl::VERTEX_SHADER,
  157. Self::Compute => gl::COMPUTE_SHADER,
  158. Self::Fragment => gl::FRAGMENT_SHADER,
  159. Self::Geometry => gl::GEOMETRY_SHADER,
  160. Self::TesslationControl => gl::TESS_CONTROL_SHADER,
  161. Self::TesslationEvaluation => gl::TESS_EVALUATION_SHADER,
  162. }
  163. }
  164. }
  165. /* Uniform */
  166. pub enum Uniform<'a> {
  167. Matrix4f(&'a Matrix4f),
  168. }