kepler_ra/techtron/webgl/
shader.rs

1// MIT License
2
3// Copyright (c) 2023 Techtron-Lab
4
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23
24use 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    // Performance,
33    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    // context.0.use_program(Some(&program));
187    Ok(program)
188}