use glow::HasContext as _;
use wasm_bindgen::JsCast;
pub struct PlatformContext {
#[allow(unused)]
webgl2: web_sys::WebGl2RenderingContext,
glow: glow::Context,
}
pub struct PlatformSurface {
info: crate::SurfaceInfo,
extent: crate::Extent,
}
#[derive(Debug)]
pub struct PlatformFrame {
framebuf: glow::Framebuffer,
extent: crate::Extent,
}
impl super::Surface {
pub fn info(&self) -> crate::SurfaceInfo {
self.platform.info
}
pub fn acquire_frame(&self) -> super::Frame {
let size = self.platform.extent;
super::Frame {
platform: PlatformFrame {
framebuf: self.framebuf,
extent: self.platform.extent,
},
texture: super::Texture {
inner: super::TextureInner::Texture {
raw: self.offscreen_texture,
target: glow::TEXTURE_2D,
},
target_size: [size.width as u16, size.height as u16],
format: self.platform.info.format,
},
}
}
}
impl PlatformContext {
pub(super) fn present(&self, frame: PlatformFrame) {
unsafe {
super::present_blit(&self.glow, frame.framebuf, frame.extent);
}
}
}
impl super::Context {
pub unsafe fn init(_desc: crate::ContextDesc) -> Result<Self, crate::NotSupportedError> {
let canvas = web_sys::window()
.and_then(|win| win.document())
.expect("Cannot get document")
.get_element_by_id("blade")
.expect("Canvas is not found")
.dyn_into::<web_sys::HtmlCanvasElement>()
.expect("Failed to downcast to canvas type");
let context_options = js_sys::Object::new();
js_sys::Reflect::set(
&context_options,
&"antialias".into(),
&wasm_bindgen::JsValue::FALSE,
)
.expect("Cannot create context options");
let webgl2 = canvas
.get_context_with_context_options("webgl2", &context_options)
.expect("Cannot create WebGL2 context")
.and_then(|context| context.dyn_into::<web_sys::WebGl2RenderingContext>().ok())
.expect("Cannot convert into WebGL2 context");
let glow = glow::Context::from_webgl2_context(webgl2.clone());
let capabilities = super::Capabilities::empty();
let limits = super::Limits {
uniform_buffer_alignment: unsafe {
glow.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT) as u32
},
};
let device_information = unsafe {
crate::DeviceInformation {
is_software_emulated: false,
device_name: glow.get_parameter_string(glow::VENDOR),
driver_name: glow.get_parameter_string(glow::RENDERER),
driver_info: glow.get_parameter_string(glow::VERSION),
}
};
Ok(super::Context {
platform: PlatformContext { webgl2, glow },
capabilities,
toggles: super::Toggles::default(),
limits,
device_information,
})
}
pub fn create_surface<I>(
&self,
_window: &I,
) -> Result<super::Surface, crate::NotSupportedError> {
let platform = PlatformSurface {
info: crate::SurfaceInfo {
format: crate::TextureFormat::Rgba8Unorm,
alpha: crate::AlphaMode::PreMultiplied,
},
extent: crate::Extent::default(),
};
Ok(unsafe {
super::Surface {
platform,
offscreen_texture: self.platform.glow.create_texture().unwrap(),
framebuf: self.platform.glow.create_framebuffer().unwrap(),
}
})
}
pub fn destroy_surface(&self, _surface: &mut super::Surface) {}
pub fn reconfigure_surface(&self, surface: &mut super::Surface, config: crate::SurfaceConfig) {
let format_desc = super::describe_texture_format(surface.platform.info.format);
let gl = &self.platform.glow;
unsafe {
gl.bind_texture(glow::TEXTURE_2D, Some(surface.offscreen_texture));
gl.tex_image_2d(
glow::TEXTURE_2D,
0,
format_desc.internal as i32,
config.size.width as _,
config.size.height as _,
0,
format_desc.external,
format_desc.data_type,
glow::PixelUnpackData::Slice(None),
);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(surface.framebuf));
gl.framebuffer_texture_2d(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
glow::TEXTURE_2D,
Some(surface.offscreen_texture),
0,
);
gl.bind_texture(glow::TEXTURE_2D, None);
}
surface.platform.extent = config.size;
}
pub(super) fn lock(&self) -> &glow::Context {
&self.platform.glow
}
}