mod atlas;
mod basic;
mod draw;
use std::num::NonZeroU32;
use std::sync::Arc;
use std::time::Instant;
pub use draw::{Draw, Shared};
use kas::cast::Cast;
use kas::draw::{SharedState, WindowCommon, color};
use kas::geom::Size;
use kas::runner::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use kas::runner::{
GraphicsFeatures, GraphicsInstance, HasDisplayAndWindowHandle, RunError, WindowSurface,
};
pub struct Instance {}
impl Instance {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Instance {}
}
}
pub struct Surface {
size: Size,
surface: softbuffer::Surface<Arc<dyn HasDisplayHandle>, Arc<dyn HasWindowHandle>>,
draw: Draw,
}
fn color_to_u32(c: impl Into<color::Rgba8Srgb>) -> u32 {
u32::from_be_bytes(c.into().0) >> 8
}
impl WindowSurface for Surface {
type Shared = Shared;
fn size(&self) -> Size {
self.size
}
fn configure(&mut self, _: &mut Shared, size: Size) -> bool {
if size == self.size() {
return false;
}
self.size = size;
self.draw.resize(size);
let width = NonZeroU32::new(size.0.cast()).expect("zero-sized surface");
let height = NonZeroU32::new(size.1.cast()).expect("zero-sized surface");
self.surface
.resize(width, height)
.expect("surface resize failed");
true
}
fn draw_iface<'iface>(
&'iface mut self,
shared: &'iface mut SharedState<Shared>,
) -> kas::draw::DrawIface<'iface, Shared> {
kas::draw::DrawIface::new(&mut self.draw, shared)
}
fn common_mut(&mut self) -> &mut WindowCommon {
&mut self.draw.common
}
fn present(&mut self, shared: &mut Shared, clear_color: color::Rgba) -> Instant {
let mut buffer = self
.surface
.buffer_mut()
.expect("failed to access surface buffer");
let width: usize = self.size.0.cast();
let height: usize = self.size.1.cast();
debug_assert_eq!(width * height, buffer.len());
let c = color_to_u32(clear_color);
buffer.fill(c);
self.draw.render(shared, &mut buffer, (width, height));
let pre_present = Instant::now();
buffer.present().expect("failed to present buffer");
pre_present
}
}
impl GraphicsInstance for Instance {
type Shared = Shared;
type Surface = Surface;
fn new_shared(&mut self, _: Option<&Surface>, _: GraphicsFeatures) -> Result<Shared, RunError> {
Ok(Shared::default())
}
fn new_surface(
&mut self,
window: std::sync::Arc<dyn HasDisplayAndWindowHandle + Send + Sync>,
_: bool,
) -> std::result::Result<Self::Surface, RunError>
where
Self: Sized,
{
let display = window.clone() as Arc<dyn HasDisplayHandle>;
let window = window as Arc<dyn HasWindowHandle>;
let context =
softbuffer::Context::new(display).map_err(|err| RunError::Graphics(Box::new(err)))?;
let surface = softbuffer::Surface::new(&context, window)
.map_err(|err| RunError::Graphics(Box::new(err)))?;
Ok(Surface {
size: Size::ZERO,
surface,
draw: Draw::default(),
})
}
}