use super::color::Rgba;
use super::{DrawImpl, PassId};
use crate::ActionRedraw;
use crate::config::RasterConfig;
use crate::geom::{Quad, Size, Vec2};
use crate::text::{Effect, TextDisplay};
use std::any::Any;
use std::num::NonZeroU32;
use std::rc::Rc;
use thiserror::Error;
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ImageId(NonZeroU32);
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ImageHandle(ImageId, Rc<()>);
impl ImageHandle {
#[inline]
pub fn id(&self) -> ImageId {
self.0
}
}
impl ImageId {
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
#[inline]
pub const fn try_new(n: u32) -> Option<Self> {
if let Some(nz) = NonZeroU32::new(n) {
Some(ImageId(nz))
} else {
None
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ImageFormat {
Rgba8,
}
#[derive(Error, Debug)]
#[error("failed to allocate: size too large or zero-sized")]
pub struct AllocError;
#[derive(Error, Debug)]
pub enum UploadError {
#[error("image_upload: unknown atlas {0}")]
AtlasIndex(u32),
#[error("image_upload: allocation not found: {0:?}")]
ImageId(ImageId),
#[error("image_upload: texture coordinates not within bounds")]
TextureCoordinates,
#[error("image_upload: bad data length (received {0} bytes)")]
DataLen(u32),
}
pub struct SharedState<DS: DrawSharedImpl> {
pub draw: DS,
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
impl<DS: DrawSharedImpl> SharedState<DS> {
pub fn new(draw: DS) -> Self {
SharedState { draw }
}
}
pub trait DrawShared {
fn image_alloc(&mut self, format: ImageFormat, size: Size) -> Result<ImageHandle, AllocError>;
fn image_upload(
&mut self,
handle: &ImageHandle,
data: &[u8],
) -> Result<ActionRedraw, UploadError>;
fn image_free(&mut self, handle: ImageHandle);
fn image_size(&self, handle: &ImageHandle) -> Option<Size>;
}
impl<DS: DrawSharedImpl> DrawShared for SharedState<DS> {
#[inline]
fn image_alloc(&mut self, format: ImageFormat, size: Size) -> Result<ImageHandle, AllocError> {
self.draw
.image_alloc(format, size)
.map(|id| ImageHandle(id, Rc::new(())))
}
#[inline]
fn image_upload(
&mut self,
handle: &ImageHandle,
data: &[u8],
) -> Result<ActionRedraw, UploadError> {
self.draw.image_upload(handle.0, data).map(|_| ActionRedraw)
}
#[inline]
fn image_free(&mut self, handle: ImageHandle) {
if let Ok(()) = Rc::try_unwrap(handle.1) {
self.draw.image_free(handle.0);
}
}
#[inline]
fn image_size(&self, handle: &ImageHandle) -> Option<Size> {
self.draw.image_size(handle.0)
}
}
pub trait DrawSharedImpl: Any {
type Draw: DrawImpl;
fn max_texture_dimension_2d(&self) -> u32;
fn set_raster_config(&mut self, config: &RasterConfig);
fn image_alloc(&mut self, format: ImageFormat, size: Size) -> Result<ImageId, AllocError>;
fn image_upload(&mut self, id: ImageId, data: &[u8]) -> Result<(), UploadError>;
fn image_free(&mut self, id: ImageId);
fn image_size(&self, id: ImageId) -> Option<Size>;
fn draw_image(&self, draw: &mut Self::Draw, pass: PassId, id: ImageId, rect: Quad);
fn draw_text(
&mut self,
draw: &mut Self::Draw,
pass: PassId,
pos: Vec2,
bb: Quad,
text: &TextDisplay,
col: Rgba,
);
fn draw_text_effects(
&mut self,
draw: &mut Self::Draw,
pass: PassId,
pos: Vec2,
bb: Quad,
text: &TextDisplay,
colors: &[Rgba],
effects: &[Effect],
);
}