1use std::rc::Rc;
2
3use glow::HasContext;
4
5use crate::{renderer::ShaderType, ErrorKind};
6
7const GLSL_VERSION: &str = "#version 100";
8
9pub(crate) struct Shader {
10 context: Rc<glow::Context>,
11 id: <glow::Context as glow::HasContext>::Shader,
12}
13
14impl 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
50impl Drop for Shader {
51 fn drop(&mut self) {
52 unsafe {
53 self.context.delete_shader(self.id);
54 }
55 }
56}
57
58pub(crate) struct Program {
59 context: Rc<glow::Context>,
60 id: <glow::Context as glow::HasContext>::Program,
61}
62
63impl 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
124impl Drop for Program {
125 fn drop(&mut self) {
126 unsafe {
127 self.context.delete_program(self.id);
128 }
129 }
130}
131
132pub 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
141impl 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