awsm/core/webgl/
context.rs

1use wasm_bindgen::prelude::*;
2use wasm_bindgen::JsCast;
3use web_sys::HtmlCanvasElement;
4
5use web_sys::{WebGl2RenderingContext, WebGlRenderingContext};
6
7use super::attributes::PartialWebGlAttribute;
8use super::buffers::PartialWebGlBuffer;
9use super::drawing::PartialWebGlDrawing;
10use super::enums::WebGlVersion;
11use super::extensions::PartialWebGlExtensions;
12use super::funcs::PartialWebGlFuncs;
13use super::misc::PartialWebGlMisc;
14use super::query::PartialWebGlQueries;
15use super::shader::PartialWebGlShaders;
16use super::textures::PartialWebGlTextures;
17use super::toggles::PartialWebGlToggle;
18use super::uniforms::PartialWebGlUniforms;
19use super::viewport::PartialWebGlViewport;
20use crate::errors::{Error, NativeError};
21use log::info;
22use serde::Serialize;
23
24pub trait PartialWebGlVersion {
25    fn awsm_get_version(&self) -> WebGlVersion;
26}
27impl PartialWebGlVersion for WebGlRenderingContext {
28    fn awsm_get_version(&self) -> WebGlVersion {
29        WebGlVersion::One
30    }
31}
32
33impl PartialWebGlVersion for WebGl2RenderingContext {
34    fn awsm_get_version(&self) -> WebGlVersion {
35        WebGlVersion::Two
36    }
37}
38
39pub trait PartialWebGlCanvas {
40    fn awsm_get_canvas(&self) -> Result<HtmlCanvasElement, Error>;
41}
42impl PartialWebGlCanvas for WebGlRenderingContext {
43    fn awsm_get_canvas(&self) -> Result<HtmlCanvasElement, Error> {
44        self.canvas()
45            .ok_or(Error::from(NativeError::WebGlCanvas))?
46            .dyn_into::<HtmlCanvasElement>()
47            .map_err(|err| Error::from(NativeError::WebGlCanvas))
48    }
49}
50
51impl PartialWebGlCanvas for WebGl2RenderingContext {
52    fn awsm_get_canvas(&self) -> Result<HtmlCanvasElement, Error> {
53        self.canvas()
54            .ok_or(Error::from(NativeError::WebGlCanvas))?
55            .dyn_into::<HtmlCanvasElement>()
56            .map_err(|err| Error::from(NativeError::WebGlCanvas))
57    }
58}
59pub trait WebGlCommon:
60    PartialWebGlVersion
61    + PartialWebGlCanvas
62    + PartialWebGlAttribute
63    + PartialWebGlQueries
64    + PartialWebGlBuffer
65    + PartialWebGlDrawing
66    + PartialWebGlExtensions
67    + PartialWebGlFuncs
68    + PartialWebGlMisc
69    + PartialWebGlShaders
70    + PartialWebGlTextures
71    + PartialWebGlToggle
72    + PartialWebGlUniforms
73    + PartialWebGlViewport
74{
75}
76
77impl WebGlCommon for WebGlRenderingContext {}
78
79impl WebGlCommon for WebGl2RenderingContext {}
80
81/* Creators */
82pub struct WebGlContextOptions {
83    pub alpha: bool,
84    pub depth: bool,
85    pub stencil: bool,
86    pub antialias: bool,
87    pub premultiplied_alpha: bool,
88    pub preserve_drawing_buffer: bool,
89    pub power_preference: PowerPreference,
90    pub fail_if_major_performance_caveat: bool,
91    pub desynchronized: bool,
92}
93
94pub enum PowerPreference {
95    Default,
96    HighPerformance,
97    LowPower,
98}
99
100impl Default for WebGlContextOptions {
101    fn default() -> Self {
102        Self {
103            alpha: true,
104            depth: true,
105            stencil: false,
106            antialias: true,
107            premultiplied_alpha: true,
108            preserve_drawing_buffer: false,
109            power_preference: PowerPreference::Default,
110            fail_if_major_performance_caveat: false,
111            desynchronized: false,
112        }
113    }
114}
115
116impl WebGlContextOptions {
117    pub fn to_js_value(&self) -> JsValue {
118        let power_preference = match self.power_preference {
119            PowerPreference::LowPower => "low-power",
120            PowerPreference::HighPerformance => "high-performance",
121            _ => "default",
122        };
123
124        let sanitized = _WebGlContextOptions {
125            alpha: self.alpha,
126            depth: self.depth,
127            stencil: self.stencil,
128            antialias: self.antialias,
129            premultiplied_alpha: self.premultiplied_alpha,
130            preserve_drawing_buffer: self.preserve_drawing_buffer,
131            power_preference,
132            fail_if_major_performance_caveat: self.fail_if_major_performance_caveat,
133            desynchronized: self.desynchronized,
134        };
135
136        serde_wasm_bindgen::to_value(&sanitized).unwrap()
137    }
138}
139
140#[derive(Serialize)]
141#[serde(rename_all = "camelCase")]
142struct _WebGlContextOptions {
143    alpha: bool,
144    depth: bool,
145    stencil: bool,
146    antialias: bool,
147    premultiplied_alpha: bool,
148    preserve_drawing_buffer: bool,
149    power_preference: &'static str,
150    fail_if_major_performance_caveat: bool,
151    desynchronized: bool,
152}
153
154pub fn get_webgl_context_1(
155    canvas: &HtmlCanvasElement,
156    opts: Option<&WebGlContextOptions>,
157) -> Result<WebGlRenderingContext, Error> {
158    info!("Webgl version 1");
159
160    let context = match opts {
161        Some(opts) => canvas.get_context_with_context_options("webgl", &opts.to_js_value()),
162        None => canvas.get_context("webgl"),
163    };
164
165    context
166        .and_then(|obj| match obj {
167            None => Err(Error::Empty.into()),
168            Some(ctx) => ctx
169                .dyn_into::<web_sys::WebGlRenderingContext>()
170                .map_err(|err| err.into()),
171        })
172        .map_err(|_| Error::Native(NativeError::WebGlContext))
173}
174pub fn get_webgl_context_2(
175    canvas: &HtmlCanvasElement,
176    opts: Option<&WebGlContextOptions>,
177) -> Result<WebGl2RenderingContext, Error> {
178    info!("Webgl version 2");
179
180    let context = match opts {
181        Some(opts) => canvas.get_context_with_context_options("webgl2", &opts.to_js_value()),
182        None => canvas.get_context("webgl2"),
183    };
184
185    context
186        .and_then(|obj| match obj {
187            None => Err(Error::Empty.into()),
188            Some(ctx) => ctx
189                .dyn_into::<web_sys::WebGl2RenderingContext>()
190                .map_err(|err| err.into()),
191        })
192        .map_err(|_| Error::Native(NativeError::WebGlContext))
193}