use super::discrete_srgb::float_to_srgb_u8;
use super::{Color, ImageSlice};
use crate::Node;
use alloc::vec::Vec;
use core::hash::{Hash, Hasher};
use dyn_any::StaticType;
use glam::{DAffine2, DVec2};
#[cfg(feature = "serde")]
mod base64_serde {
//! Basic wrapper for [`serde`] to perform [`base64`] encoding
use super::super::Pixel;
use serde::{Deserialize, Deserializer, Serializer};
pub fn as_base64(key: &Vec
, serializer: S) -> Result ,
}
impl {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let length = self.data.len();
f.debug_struct("Image")
.field("width", &self.width)
.field("height", &self.height)
.field("data", if length < 100 { &self.data } else { &length })
.finish()
}
}
unsafe impl
where
P::Static: Pixel,
{
type Static = Image {
type Pixel = P;
fn get_pixel(&self, x: u32, y: u32) -> Option {
self.data.get((x + y * self.width) as usize).copied()
}
fn width(&self) -> u32 {
self.width
}
fn height(&self) -> u32 {
self.height
}
}
impl {
fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut P> {
self.data.get_mut((x + y * self.width) as usize)
}
}
// TODO: Evaluate if this will be a problem for our use case.
/// Warning: This is an approximation of a hash, and is not guaranteed to not collide.
impl {
fn hash {
pub const fn empty() -> Self {
Self {
width: 0,
height: 0,
data: Vec::new(),
}
}
pub fn new(width: u32, height: u32, color: P) -> Self {
Self {
width,
height,
data: vec![color; (width * height) as usize],
}
}
pub fn as_slice(&self) -> ImageSlice {
ImageSlice {
width: self.width,
height: self.height,
data: self.data.as_slice(),
}
}
}
impl Image
where
P::ColorChannel: Linear,
::AlphaChannel: Linear,
{
/// Flattens each channel cast to a u8
pub fn into_flat_u8(self) -> (Vec {
type Item = P;
type IntoIter = alloc::vec::IntoIter ;
fn into_iter(self) -> Self::IntoIter {
self.data.into_iter()
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ImageRefNode {
_p: PhantomData ,
}
#[node_macro::node_fn(ImageRefNode<_P>)]
fn image_ref_node<_P: Pixel>(image: &'input Image<_P>) -> ImageSlice<'input, _P> {
image.as_slice()
}
#[derive(Debug, Clone)]
pub struct CollectNode {}
#[node_macro::node_fn(CollectNode)]
fn collect_node<_Iter>(input: _Iter) -> Vec<_Iter::Item>
where
_Iter: Iterator,
{
input.collect()
}
#[derive(Debug)]
pub struct MapImageSliceNode {
data: Data,
}
#[node_macro::node_fn(MapImageSliceNode)]
fn map_node ) -> Image {
Image {
width: input.0,
height: input.1,
data,
}
}
#[derive(Clone, Debug, PartialEq, Default, specta::Type)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ImageFrame ,
pub transform: DAffine2,
}
impl {
type Pixel = P;
// TODO: Improve sampling logic
fn sample(&self, pos: DVec2, _area: DVec2) -> Option {
type Pixel = P;
fn width(&self) -> u32 {
self.image.width()
}
fn height(&self) -> u32 {
self.image.height()
}
fn get_pixel(&self, x: u32, y: u32) -> Option {
fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> {
self.image.get_pixel_mut(x, y)
}
}
unsafe impl
where
P::Static: Pixel,
{
type Static = ImageFrame {
pub const fn empty() -> Self {
Self {
image: Image::empty(),
transform: DAffine2::ZERO,
}
}
pub const fn identity() -> Self {
Self {
image: Image::empty(),
transform: DAffine2::IDENTITY,
}
}
pub fn get_mut(&mut self, x: usize, y: usize) -> &mut P {
&mut self.image.data[y * (self.image.width as usize) + x]
}
/// Clamps the provided point to ((0, 0), (ImageSize.x, ImageSize.y)) and returns the closest pixel
pub fn sample(&self, position: DVec2) -> P {
let x = position.x.clamp(0., self.image.width as f64 - 1.) as usize;
let y = position.y.clamp(0., self.image.height as f64 - 1.) as usize;
self.image.data[x + y * self.image.width as usize]
}
}
impl {
fn as_ref(&self) -> &ImageFrame {
self
}
}
impl {
fn hash