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
 98
 99
100
101
102
103
104
105
106
107
108
//! Glow backend for Luminance
//!
//! This crate provides a [glow] backend for [luminance]. It is capable of targeting desktop using
//! OpenGL and web using both WebGL 2 and WebGL 1 ( though WebGL 1 has some caveats such as
//! supported texture formats ).
//!
//! [luminance]: https://crates.io/crates/luminance
//!
//! [glow]: https://github.com/grovesNL/glow

use std::cell::RefCell;
use std::rc::Rc;

#[macro_use]
mod slice;

mod buffer;
mod framebuffer;
mod pipeline;
mod pixel;
mod shader;
mod state;
mod tess;
mod texture;

use glow::Context as GlowContext;

use state::GlowState;
pub use state::StateQueryError;

/// The GLSL shader version to use
///
/// This effects the version heading added automatically to the top of the shader strings provided
/// to luminance.
#[derive(Debug, Clone, Copy)]
pub enum ShaderVersion {
    Gles3,
    Gles1,
}

/// The graphics context which must be provided to create a [`Glow`] backend
pub struct Context {
    glow_context: GlowContext,
    is_webgl1: bool,
    shader_version: ShaderVersion,
}

impl Context {
    /// Create a native context from a GL loader function
    #[cfg(not(wasm))]
    pub unsafe fn from_loader_function<F>(loader_function: F, shader_version: ShaderVersion) -> Self
    where
        F: FnMut(&str) -> *const std::os::raw::c_void,
    {
        Self {
            glow_context: GlowContext::from_loader_function(loader_function),
            is_webgl1: false,
            shader_version,
        }
    }

    /// Create a WebGL 1 context
    ///
    /// > ⚠️ **Warning:** The WebGL 1 backend has limitations that the native and WebGL 2 bakcends
    /// > to not have. The exact limitations are outside of the scope of this note, but include
    /// > things like limited support for different pixel formats, etc.
    #[cfg(wasm)]
    pub fn from_webgl1_context(context: web_sys::WebGlRenderingContext) -> Self {
        Self {
            glow_context: GlowContext::from_webgl1_context(context),
            is_webgl1: true,
            shader_version: ShaderVersion::Gles1,
        }
    }

    /// Create a WebGL 2 context
    #[cfg(wasm)]
    pub fn from_webgl2_context(
        context: web_sys::WebGl2RenderingContext,
        shader_version: ShaderVersion,
    ) -> Self {
        Self {
            glow_context: GlowContext::from_webgl2_context(context),
            is_webgl1: false,
            shader_version,
        }
    }
}

/// The Luminance Glow backend
#[derive(Debug)]
pub struct Glow {
    pub(crate) state: Rc<RefCell<GlowState>>,
}

impl Glow {
    /// Create a glow backend instance from a `glow` [`Context`][glow::Context]
    pub fn from_context(ctx: Context) -> Result<Self, StateQueryError> {
        let Context {
            glow_context,
            is_webgl1,
            shader_version,
        } = ctx;
        GlowState::new(glow_context, is_webgl1, shader_version).map(|state| Glow {
            state: Rc::new(RefCell::new(state)),
        })
    }
}