1use std::fmt;
4use web_sys::WebGlProgram;
5use web_sys::WebGlShader;
6use web_sys::WebGlUniformLocation;
7
8use crate::{gl, GL};
9
10#[repr(u32)]
12pub enum ShaderType {
13 VERTEX = GL::VERTEX_SHADER,
15 FRAGMENT = GL::FRAGMENT_SHADER,
17}
18
19#[derive(Debug)]
23pub struct Shader {
24 pub name: &'static str,
26 program: Option<WebGlProgram>,
27}
28
29impl Default for Shader {
30 fn default() -> Self {
31 Self {
32 name: "Uninitialized Shader",
33 program: None,
34 }
35 }
36}
37
38impl fmt::Display for Shader {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 if self.program.is_some() {
41 write!(f, "{}", self.name)
42 } else {
43 write!(f, "{} (SHADER PROGRAM MISSING)", self.name)
44 }
45 }
46}
47
48impl gl::Bind for Shader {
49 fn bind(&self, gl: &GL) {
51 gl.use_program(self.program.as_ref());
52 }
53 fn unbind(&self, gl: &GL) {
54 gl.use_program(None);
55 }
56}
57
58impl Drop for Shader {
59 fn drop(&mut self) {
60 let gl = gl::get_context();
61 gl.delete_program(self.program.as_ref());
62 }
63}
64
65impl Shader {
66 pub fn new(gl: &GL) -> Self {
68 let name = "Default Shader";
69 let vertex_shader =
70 Shader::create_vertex(gl, include_str!("../res/shader/default.vert.glsl"))
71 .expect("Could not create Vertex Shader!");
72
73 let fragment_shader =
74 Shader::create_fragment(gl, include_str!("../res/shader/default.frag.glsl"))
75 .expect("Could not create Fragment Shader!");
76
77 let program =
78 Shader::program_with_vertex_and_fragment(gl, &vertex_shader, &fragment_shader).ok();
79
80 Self { name, program }
81 }
82
83 pub fn new_with_vertex(
85 gl: &GL,
86 vertex_shader: WebGlShader,
87 name: Option<&'static str>,
88 ) -> Self {
89 let name = name.unwrap_or("Custom Vertex Shader");
90
91 let fragment_shader =
92 Shader::create_fragment(gl, include_str!("../res/shader/default.frag.glsl"))
93 .expect("Could not create Fragment Shader!");
94
95 let program =
96 Shader::program_with_vertex_and_fragment(gl, &vertex_shader, &fragment_shader).ok();
97
98 Self { name, program }
99 }
100
101 pub fn create_fragment(gl: &GL, source: &str) -> Result<WebGlShader, String> {
103 Self::create_with_type(gl, ShaderType::FRAGMENT, source)
104 }
105
106 pub fn create_vertex(gl: &GL, source: &str) -> Result<WebGlShader, String> {
108 Self::create_with_type(gl, ShaderType::VERTEX, source)
109 }
110
111 pub fn create_with_type(
113 gl: &GL,
114 shader_type: ShaderType,
115 source: &str,
116 ) -> Result<WebGlShader, String> {
117 let shader = gl
118 .create_shader(shader_type as u32)
119 .ok_or_else(|| String::from("Unable to create Shader object."))?;
120 gl.shader_source(&shader, source);
121 gl.compile_shader(&shader);
122
123 if gl
124 .get_shader_parameter(&shader, GL::COMPILE_STATUS)
125 .as_bool()
126 .unwrap_or(false)
127 {
128 Ok(shader)
129 } else {
130 Err(gl
131 .get_shader_info_log(&shader)
132 .unwrap_or_else(|| String::from("Could not compile shader.")))
133 }
134 }
135
136 pub fn program_with_vertex_and_fragment(
138 gl: &GL,
139 vertex_shader: &WebGlShader,
140 fragment_shader: &WebGlShader,
141 ) -> Result<WebGlProgram, String> {
142 let program = gl
143 .create_program()
144 .ok_or_else(|| String::from("Unable to create Program object."))?;
145 gl.attach_shader(&program, vertex_shader);
146 gl.attach_shader(&program, fragment_shader);
147 gl.link_program(&program);
148
149 if gl
150 .get_program_parameter(&program, GL::LINK_STATUS)
151 .as_bool()
152 .unwrap_or(false)
153 {
154 gl.delete_shader(Some(vertex_shader));
155 gl.delete_shader(Some(fragment_shader));
156 Ok(program)
157 } else {
158 Err(gl
159 .get_program_info_log(&program)
160 .unwrap_or_else(|| String::from("Could not link program.")))
161 }
162 }
163
164 pub fn get_uniform_location(&self, gl: &GL, name: &str) -> Option<WebGlUniformLocation> {
166 self.program
167 .as_ref()
168 .map(|program| gl.get_uniform_location(program, name))
169 .unwrap()
170 }
171
172 pub fn get_attrib_location(&self, gl: &GL, name: &str) -> Option<i32> {
174 self.program
175 .as_ref()
176 .map(|program| gl.get_attrib_location(program, name))
177 }
178}