kepler_ra/techtron/webgl/
shader.rs1use std::{
25 ops::{Deref, DerefMut},
26 rc::Rc,
27};
28
29use js_sys::{Array, ArrayBuffer, Float32Array};
30use wasm_bindgen::{JsCast, JsValue};
31use web_sys::{
32 WebGl2RenderingContext,
34 WebGlProgram,
35 WebGlShader,
36 WebGlTexture,
37};
38
39use super::texture::LoadedTexture;
40
41use super::{context::GLContext, program::Program};
42
43type GL2 = WebGl2RenderingContext;
44
45#[derive(Debug, Clone)]
46pub struct ShaderSource(pub String);
47
48impl ShaderSource {
49 pub fn new(source: &str) -> Self {
50 Self(String::from(source))
51 }
52
53 pub fn to_vertex(&self) -> VertexShader {
54 VertexShader {
55 source: self.clone(),
56 }
57 }
58
59 pub fn to_fragment(&self) -> FragmentShader {
60 FragmentShader {
61 source: self.clone(),
62 }
63 }
64}
65
66#[derive(Debug, Clone)]
67pub struct VertexShader {
68 pub source: ShaderSource,
69}
70
71impl VertexShader {
72 pub fn compile(&self, context: &GLContext) -> Result<CompiledVertexShader, String> {
73 let handle = compile_shader(
74 &context,
75 WebGl2RenderingContext::VERTEX_SHADER,
76 &self.source.0,
77 )?;
78 Ok(CompiledVertexShader {
79 handle,
80 context: context.clone(),
81 })
82 }
83}
84
85#[derive(Debug, Clone)]
86pub struct FragmentShader {
87 pub source: ShaderSource,
88}
89
90impl FragmentShader {
91 pub fn compile(&self, context: &GLContext) -> Result<CompiledFragmentShader, String> {
92 let handle = compile_shader(
93 &context,
94 WebGl2RenderingContext::FRAGMENT_SHADER,
95 &self.source.0,
96 )?;
97 Ok(CompiledFragmentShader {
98 handle,
99 context: context.clone(),
100 })
101 }
102}
103
104#[derive(Debug, PartialEq, Eq)]
105pub struct CompiledVertexShader {
106 pub handle: WebGlShader,
107 pub context: GLContext,
108}
109
110impl Drop for CompiledVertexShader {
111 fn drop(&mut self) {
112 self.context.delete_shader(Some(&self.handle))
113 }
114}
115
116impl Deref for CompiledVertexShader {
117 type Target = WebGlShader;
118 fn deref(&self) -> &Self::Target {
119 &self.handle
120 }
121}
122
123#[derive(Debug, Clone, PartialEq, Eq)]
124pub struct CompiledFragmentShader {
125 pub handle: WebGlShader,
126 pub context: GLContext,
127}
128
129impl Drop for CompiledFragmentShader {
130 fn drop(&mut self) {
131 self.context.delete_shader(Some(&self.handle))
132 }
133}
134
135impl Deref for CompiledFragmentShader {
136 type Target = WebGlShader;
137 fn deref(&self) -> &Self::Target {
138 &self.handle
139 }
140}
141
142pub fn compile_shader(
143 context: &WebGl2RenderingContext,
144 shader_type: u32,
145 source: &str,
146) -> Result<WebGlShader, String> {
147 let shader = context
148 .create_shader(shader_type)
149 .ok_or_else(|| String::from("Unable to create shader object"))?;
150 context.shader_source(&shader, source);
151 context.compile_shader(&shader);
152
153 if context
154 .get_shader_parameter(&shader, WebGl2RenderingContext::COMPILE_STATUS)
155 .as_bool()
156 .unwrap_or(false)
157 {
158 Ok(shader)
159 } else {
160 let shader_type_str = match shader_type {
161 WebGl2RenderingContext::FRAGMENT_SHADER => "Fragment shader: ",
162 WebGl2RenderingContext::VERTEX_SHADER => "Vertex shader: ",
163 _ => panic!("never be here!"),
164 };
165 Err(format!(
166 "{}{}",
167 shader_type_str,
168 context
169 .get_shader_info_log(&shader)
170 .unwrap_or_else(|| String::from("Unknown error creating shader"))
171 ))
172 }
173}
174
175pub fn load_shaders(
176 context: &WebGl2RenderingContext,
177 vert_src: &str,
178 frag_src: &str,
179) -> Result<Program, JsValue> {
180 let context = GLContext::new(context.clone());
181 let vert_shader = ShaderSource::new(vert_src).to_vertex().compile(&context)?;
182 let frag_shader = ShaderSource::new(frag_src)
183 .to_fragment()
184 .compile(&context)?;
185 let program = Program::new(&context, vert_shader, frag_shader);
186 Ok(program)
188}