use image_texel::image::{ImageMut, ImageRef};
use image_texel::Image;
use crate::color::Color;
use crate::layout::{CanvasLayout, ChannelLayout, LayoutError, PlanarLayout, PlaneBytes};
use crate::shader::Converter;
#[derive(Clone)]
pub struct Canvas {
inner: Image<CanvasLayout>,
}
#[derive(Clone)]
pub struct Plane {
inner: Image<PlaneBytes>,
}
#[doc(hidden)]
#[deprecated = "Use BytePlaneRef"]
pub type BytePlane<'data> = BytePlaneRef<'data>;
pub struct BytePlaneRef<'data> {
inner: ImageRef<'data, PlaneBytes>,
}
pub struct BytePlaneMut<'data> {
inner: ImageMut<'data, PlaneBytes>,
}
pub struct PlaneRef<'data, T> {
inner: ImageRef<'data, PlanarLayout<T>>,
}
pub struct PlaneMut<'data, T> {
inner: ImageMut<'data, PlanarLayout<T>>,
}
pub struct ChannelsRef<'data, C> {
inner: ImageRef<'data, ChannelLayout<C>>,
}
pub struct ChannelsMut<'data, C> {
inner: ImageMut<'data, ChannelLayout<C>>,
}
impl Canvas {
pub fn new(layout: CanvasLayout) -> Self {
Canvas {
inner: Image::new(layout),
}
}
pub fn layout(&self) -> &CanvasLayout {
self.inner.layout()
}
pub fn set_layout(&mut self, layout: CanvasLayout) {
self.set_layout_conservative(layout);
self.inner.as_bytes_mut().fill(0);
}
pub fn set_layout_conservative(&mut self, layout: CanvasLayout) {
*self.inner.layout_mut_unguarded() = layout;
self.inner.ensure_layout();
}
pub fn as_bytes(&self) -> &[u8] {
self.inner.as_bytes()
}
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
self.inner.as_bytes_mut()
}
pub fn as_texels<T>(&self, texel: image_texel::Texel<T>) -> &[T] {
self.inner.as_texels(texel)
}
pub fn as_texels_mut<T>(&mut self, texel: image_texel::Texel<T>) -> &mut [T] {
self.inner.as_mut_texels(texel)
}
pub fn channels_u8(&self) -> Option<ChannelsRef<u8>> {
let plane = self.inner.layout().as_plane()?;
let layout = plane
.as_channel_bytes()?
.is_compatible(<u8 as image_texel::AsTexel>::texel())?;
Some(ChannelsRef {
inner: self.inner.as_ref().with_layout(layout)?,
})
}
pub fn channels_u16(&self) -> Option<ChannelsRef<u16>> {
let plane = self.inner.layout().as_plane()?;
let layout = plane
.as_channel_bytes()?
.is_compatible(<u16 as image_texel::AsTexel>::texel())?;
Some(ChannelsRef {
inner: self.inner.as_ref().with_layout(layout)?,
})
}
pub fn channels_f32(&self) -> Option<ChannelsRef<f32>> {
let plane = self.inner.layout().as_plane()?;
let layout = plane
.as_channel_bytes()?
.is_compatible(<f32 as image_texel::AsTexel>::texel())?;
Some(ChannelsRef {
inner: self.inner.as_ref().with_layout(layout)?,
})
}
pub fn channels_u8_mut(&mut self) -> Option<ChannelsMut<u8>> {
let plane = self.inner.layout().as_plane()?;
let layout = plane
.as_channel_bytes()?
.is_compatible(<u8 as image_texel::AsTexel>::texel())?;
Some(ChannelsMut {
inner: self.inner.as_mut().with_layout(layout)?,
})
}
pub fn channels_u16_mut(&mut self) -> Option<ChannelsMut<u16>> {
let plane = self.inner.layout().as_plane()?;
let layout = plane
.as_channel_bytes()?
.is_compatible(<u16 as image_texel::AsTexel>::texel())?;
Some(ChannelsMut {
inner: self.inner.as_mut().with_layout(layout)?,
})
}
pub fn channels_f32_mut(&mut self) -> Option<ChannelsMut<f32>> {
let plane = self.inner.layout().as_plane()?;
let layout = plane
.as_channel_bytes()?
.is_compatible(<f32 as image_texel::AsTexel>::texel())?;
Some(ChannelsMut {
inner: self.inner.as_mut().with_layout(layout)?,
})
}
pub fn into_bytes(self) -> Vec<u8> {
self.as_bytes().to_owned()
}
pub fn plane(&self, idx: u8) -> Option<BytePlaneRef<'_>> {
let layout = self.layout().plane(idx)?;
Some(BytePlaneRef {
inner: self.inner.as_ref().with_layout(layout)?,
})
}
pub fn planes<const N: usize>(&self) -> Option<[BytePlaneRef<'_>; N]> {
todo!()
}
pub fn plane_mut(&mut self, idx: u8) -> Option<BytePlaneMut<'_>> {
let layout = self.layout().plane(idx)?;
Some(BytePlaneMut {
inner: self.inner.as_mut().with_layout(layout)?,
})
}
pub fn planes_mut<const N: usize>(&mut self) -> Option<[BytePlaneMut<'_>; N]> {
use image_texel::layout::Bytes;
let mut layouts = [(); N].map(|()| None);
for i in 0..N {
if i > u8::MAX as usize {
return None;
}
layouts[i] = Some(self.layout().plane(i as u8)?);
}
let layouts = layouts.map(|layout| layout.unwrap());
let mut offset = 0;
let frame: ImageMut<'_, Bytes> = self.as_mut().decay().expect("decay to bytes valid");
let &Bytes(total_len) = frame.layout();
let mut frame = frame.with_layout(Bytes(0)).expect("zero-byte layout valid");
let planes = layouts.map(move |mut layout| {
layout.sub_offset(offset);
let mut plane = frame
.split_layout()
.with_layout(layout)
.expect("plane layout within frame");
let tail = plane.split_layout();
let &Bytes(tail_len) = tail.layout();
frame = tail.with_layout(Bytes(0)).expect("zero-byte layout valid");
offset = total_len - tail_len;
Some(plane)
});
if planes.iter().any(|p| p.is_none()) {
return None;
}
Some(planes.map(|p| BytePlaneMut { inner: p.unwrap() }))
}
pub fn set_color(&mut self, color: Color) -> Result<(), LayoutError> {
self.inner.layout_mut_unguarded().set_color(color)
}
pub(crate) fn as_ref(&self) -> ImageRef<'_, &'_ CanvasLayout> {
self.inner.as_ref()
}
pub(crate) fn as_mut(&mut self) -> ImageMut<'_, &'_ mut CanvasLayout> {
self.inner.as_mut()
}
}
impl Canvas {
pub fn convert(&self, into: &mut Self) {
Converter::new().run_on(self, into)
}
}
impl<'data> BytePlaneRef<'data> {
pub fn layout(&self) -> &PlaneBytes {
self.inner.layout()
}
pub fn to_owned(&self) -> Plane {
let plane = self.inner.layout();
let bytes = self.inner.as_bytes();
Plane {
inner: Image::with_bytes(plane.clone(), bytes),
}
}
pub fn to_canvas(&self) -> Canvas {
let plane = self.inner.layout();
let bytes = self.inner.as_bytes();
Canvas {
inner: Image::with_bytes(plane.into(), bytes),
}
}
pub fn as_texels<T>(self, texel: image_texel::Texel<T>) -> Option<PlaneRef<'data, T>> {
if let Some(layout) = self.inner.layout().is_compatible(texel) {
Some(PlaneRef {
inner: self.inner.with_layout(layout).unwrap(),
})
} else {
None
}
}
}
impl<'data> BytePlaneMut<'data> {
pub fn layout(&self) -> &PlaneBytes {
self.inner.layout()
}
pub fn to_owned(&self) -> Plane {
let plane = self.inner.layout();
let bytes = self.inner.as_bytes();
Plane {
inner: Image::with_bytes(plane.clone(), bytes),
}
}
pub fn to_canvas(&self) -> Canvas {
let plane = self.inner.layout();
let bytes = self.inner.as_bytes();
Canvas {
inner: Image::with_bytes(plane.into(), bytes),
}
}
pub fn as_texels<T>(self, texel: image_texel::Texel<T>) -> Option<PlaneRef<'data, T>> {
if let Some(layout) = self.inner.layout().is_compatible(texel) {
Some(PlaneRef {
inner: self.inner.into_ref().with_layout(layout).unwrap(),
})
} else {
None
}
}
pub fn as_mut_texels<T>(self, texel: image_texel::Texel<T>) -> Option<PlaneMut<'data, T>> {
if let Some(layout) = self.inner.layout().is_compatible(texel) {
Some(PlaneMut {
inner: self.inner.with_layout(layout).unwrap(),
})
} else {
None
}
}
}
impl<'data, C> ChannelsRef<'data, C> {
pub fn layout(&self) -> &ChannelLayout<C> {
self.inner.layout()
}
pub fn as_slice(&self) -> &[C] {
self.inner.as_slice()
}
pub fn into_slice(self) -> &'data [C] {
self.inner.into_slice()
}
}
impl<'data, C> ChannelsMut<'data, C> {
pub fn layout(&self) -> &ChannelLayout<C> {
self.inner.layout()
}
pub fn as_slice(&self) -> &[C] {
self.inner.as_slice()
}
pub fn as_mut_slice(&mut self) -> &mut [C] {
self.inner.as_mut_slice()
}
pub fn into_slice(self) -> &'data [C] {
self.inner.into_slice()
}
pub fn into_mut_slice(self) -> &'data mut [C] {
self.inner.into_mut_slice()
}
}
impl<'data, T> From<PlaneRef<'data, T>> for BytePlaneRef<'data> {
fn from(plane: PlaneRef<'data, T>) -> Self {
BytePlaneRef {
inner: plane.inner.decay().unwrap(),
}
}
}
impl<'data, T> From<PlaneMut<'data, T>> for BytePlaneMut<'data> {
fn from(plane: PlaneMut<'data, T>) -> Self {
BytePlaneMut {
inner: plane.inner.decay().unwrap(),
}
}
}
impl From<Plane> for Canvas {
fn from(plane: Plane) -> Self {
Canvas {
inner: plane.inner.decay(),
}
}
}