1 | use std::rc::Rc; |
2 | |
3 | use glow::HasContext; |
4 | |
5 | use crate::{renderer::ShaderType, ErrorKind}; |
6 | |
7 | const GLSL_VERSION: &str = "#version 100" ; |
8 | |
9 | pub(crate) struct Shader { |
10 | context: Rc<glow::Context>, |
11 | id: <glow::Context as glow::HasContext>::Shader, |
12 | } |
13 | |
14 | impl Shader { |
15 | pub fn new(context: &Rc<glow::Context>, src: &str, kind: u32) -> Result<Self, ErrorKind> { |
16 | let id = unsafe { context.create_shader(kind).unwrap() }; |
17 | |
18 | // Compile |
19 | unsafe { |
20 | context.shader_source(id, src); |
21 | context.compile_shader(id); |
22 | } |
23 | |
24 | // Validate |
25 | |
26 | let success = unsafe { context.get_shader_compile_status(id) }; |
27 | if !success { |
28 | let error = unsafe { context.get_shader_info_log(id) }; |
29 | |
30 | let name = match kind { |
31 | glow::VERTEX_SHADER => "Vertex stage" , |
32 | glow::FRAGMENT_SHADER => "Fragment stage" , |
33 | _ => "Shader stage" , |
34 | }; |
35 | |
36 | return Err(ErrorKind::ShaderCompileError(format!(" {name}: {error}" ))); |
37 | } |
38 | |
39 | Ok(Shader { |
40 | context: context.clone(), |
41 | id, |
42 | }) |
43 | } |
44 | |
45 | pub fn id(&self) -> <glow::Context as glow::HasContext>::Shader { |
46 | self.id |
47 | } |
48 | } |
49 | |
50 | impl Drop for Shader { |
51 | fn drop(&mut self) { |
52 | unsafe { |
53 | self.context.delete_shader(self.id); |
54 | } |
55 | } |
56 | } |
57 | |
58 | pub(crate) struct Program { |
59 | context: Rc<glow::Context>, |
60 | id: <glow::Context as glow::HasContext>::Program, |
61 | } |
62 | |
63 | impl Program { |
64 | pub fn new(context: &Rc<glow::Context>, shaders: &[Shader], attrib_locations: &[&str]) -> Result<Self, ErrorKind> { |
65 | let program = Self { |
66 | context: context.clone(), |
67 | id: unsafe { context.create_program().unwrap() }, |
68 | }; |
69 | |
70 | // Attach stages |
71 | for shader in shaders { |
72 | unsafe { |
73 | context.attach_shader(program.id, shader.id()); |
74 | } |
75 | } |
76 | |
77 | for (i, loc) in attrib_locations.iter().enumerate() { |
78 | unsafe { |
79 | context.bind_attrib_location(program.id, i as u32, loc); |
80 | } |
81 | } |
82 | |
83 | unsafe { |
84 | context.link_program(program.id); |
85 | } |
86 | |
87 | // Check for error |
88 | |
89 | let success = unsafe { context.get_program_link_status(program.id) }; |
90 | |
91 | if !success { |
92 | let error = unsafe { context.get_program_info_log(program.id) }; |
93 | |
94 | return Err(ErrorKind::ShaderLinkError(error)); |
95 | } |
96 | |
97 | // Detach stages |
98 | for shader in shaders { |
99 | unsafe { |
100 | context.detach_shader(program.id, shader.id()); |
101 | } |
102 | } |
103 | |
104 | Ok(program) |
105 | } |
106 | |
107 | pub(crate) fn bind(&self) { |
108 | unsafe { |
109 | self.context.use_program(Some(self.id)); |
110 | } |
111 | } |
112 | |
113 | pub(crate) fn unbind(&self) { |
114 | unsafe { |
115 | self.context.use_program(None); |
116 | } |
117 | } |
118 | |
119 | fn uniform_location(&self, name: &str) -> Option<<glow::Context as glow::HasContext>::UniformLocation> { |
120 | unsafe { self.context.get_uniform_location(self.id, name) } |
121 | } |
122 | } |
123 | |
124 | impl Drop for Program { |
125 | fn drop(&mut self) { |
126 | unsafe { |
127 | self.context.delete_program(self.id); |
128 | } |
129 | } |
130 | } |
131 | |
132 | pub struct MainProgram { |
133 | context: Rc<glow::Context>, |
134 | program: Program, |
135 | loc_viewsize: <glow::Context as glow::HasContext>::UniformLocation, |
136 | loc_tex: Option<<glow::Context as glow::HasContext>::UniformLocation>, |
137 | loc_glyphtex: Option<<glow::Context as glow::HasContext>::UniformLocation>, |
138 | loc_frag: Option<<glow::Context as glow::HasContext>::UniformLocation>, |
139 | } |
140 | |
141 | impl MainProgram { |
142 | pub(crate) fn new( |
143 | context: &Rc<glow::Context>, |
144 | antialias: bool, |
145 | shader_type: ShaderType, |
146 | with_glyph_texture: bool, |
147 | ) -> Result<Self, ErrorKind> { |
148 | let shader_defs = if antialias { "#define EDGE_AA 1" } else { "" }; |
149 | let select_shader_type = format!( |
150 | "#define SELECT_SHADER {}\n{}" , |
151 | shader_type.to_u8(), |
152 | if with_glyph_texture { |
153 | "#define ENABLE_GLYPH_TEXTURE" |
154 | } else { |
155 | "" |
156 | } |
157 | ); |
158 | let vert_shader_src = format!(" {}\n{}\n{}" , GLSL_VERSION, shader_defs, include_str!("main-vs.glsl" )); |
159 | let frag_shader_src = format!( |
160 | " {}\n{}\n{}\n{}" , |
161 | GLSL_VERSION, |
162 | shader_defs, |
163 | select_shader_type, |
164 | include_str!("main-fs.glsl" ) |
165 | ); |
166 | |
167 | let vert_shader = Shader::new(context, &vert_shader_src, glow::VERTEX_SHADER)?; |
168 | let frag_shader = Shader::new(context, &frag_shader_src, glow::FRAGMENT_SHADER)?; |
169 | |
170 | let program = Program::new(context, &[vert_shader, frag_shader], &["vertex" , "tcoord" ])?; |
171 | |
172 | let loc_viewsize = program.uniform_location("viewSize" ).unwrap(); |
173 | let loc_tex = program.uniform_location("tex" ); |
174 | let loc_glyphtex = program.uniform_location("glyphtex" ); |
175 | let loc_frag = program.uniform_location("frag" ); |
176 | |
177 | Ok(Self { |
178 | context: context.clone(), |
179 | program, |
180 | loc_viewsize, |
181 | loc_tex, |
182 | loc_glyphtex, |
183 | loc_frag, |
184 | }) |
185 | } |
186 | |
187 | pub(crate) fn set_tex(&self, tex: i32) { |
188 | unsafe { |
189 | self.context.uniform_1_i32(self.loc_tex.as_ref(), tex); |
190 | } |
191 | } |
192 | |
193 | pub(crate) fn set_glyphtex(&self, tex: i32) { |
194 | unsafe { |
195 | self.context.uniform_1_i32(self.loc_glyphtex.as_ref(), tex); |
196 | } |
197 | } |
198 | |
199 | pub(crate) fn set_view(&self, view: [f32; 2]) { |
200 | unsafe { |
201 | self.context.uniform_2_f32_slice(Some(&self.loc_viewsize), &view); |
202 | } |
203 | } |
204 | |
205 | pub(crate) fn set_config(&self, config: &[f32]) { |
206 | unsafe { |
207 | self.context.uniform_4_f32_slice(self.loc_frag.as_ref(), config); |
208 | } |
209 | } |
210 | |
211 | pub(crate) fn bind(&self) { |
212 | self.program.bind(); |
213 | } |
214 | |
215 | pub(crate) fn unbind(&self) { |
216 | self.program.unbind(); |
217 | } |
218 | } |
219 | |