1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use super::*;

pub(crate) struct UgliImpl {
    pub(crate) raw: raw::Context,
    phantom_data: PhantomData<*mut ()>,
}

#[derive(Clone)]
pub struct Ugli {
    pub(crate) inner: Rc<UgliImpl>,
}

#[cfg(target_arch = "wasm32")]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WebGLContextOptions {
    pub alpha: bool,
    pub preserve_drawing_buffer: bool,
    pub stencil: bool,
    pub premultiplied_alpha: bool,
    pub power_preference: &'static str,
    pub depth: bool,
    pub antialias: bool,
}

#[cfg(target_arch = "wasm32")]
impl Default for WebGLContextOptions {
    fn default() -> Self {
        Self {
            alpha: false,
            preserve_drawing_buffer: true,
            stencil: false,
            premultiplied_alpha: false,
            power_preference: "high-performance",
            depth: true,
            antialias: false,
        }
    }
}

#[cfg(target_arch = "wasm32")]
impl Ugli {
    pub fn create_webgl(canvas: &web_sys::HtmlCanvasElement, options: WebGLContextOptions) -> Self {
        let context_options = serde_wasm_bindgen::to_value(&options).unwrap();
        let webgl;
        if let Some(context) = canvas
            .get_context_with_context_options("webgl", &context_options)
            .unwrap()
        {
            webgl = context;
        } else if let Some(context) = canvas
            .get_context_with_context_options("experimental-webgl", &context_options)
            .unwrap()
        {
            webgl = context;
        } else {
            panic!("Could not get webgl context");
        }
        let webgl: web_sys::WebGlRenderingContext = webgl.dyn_into().unwrap();
        let ugli = Ugli {
            inner: Rc::new(UgliImpl {
                raw: raw::Context::new(webgl),
                phantom_data: PhantomData,
            }),
        };
        ugli.init();
        ugli
    }
}

#[cfg(not(target_arch = "wasm32"))]
impl Ugli {
    pub fn create_from_glutin<F: Fn(&str) -> *const std::os::raw::c_void>(
        get_proc_address: F,
    ) -> Self {
        let ugli = Ugli {
            inner: Rc::new(UgliImpl {
                raw: raw::Context::new(get_proc_address),
                phantom_data: PhantomData,
            }),
        };
        ugli.init();
        ugli
    }
}

impl Ugli {
    pub fn init(&self) {
        let gl = &self.inner.raw;
        log::info!("GL version: {:?}", gl.get_version_string());
        gl.enable(raw::DEPTH_TEST);
        #[cfg(not(any(target_arch = "wasm32", target_os = "android")))]
        gl.enable(raw::PROGRAM_POINT_SIZE);
        gl.pixel_store(raw::UNPACK_ALIGNMENT, 1);
        self.check();
    }
}