diff --git a/.gitignore b/.gitignore index 5f7e373..9666c84 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ target/ /Cargo.lock .vscode/ imported_assets/ +.DS_Store diff --git a/Cargo.toml b/Cargo.toml index d9d1523..ca60300 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ anyhow = "1.0" event-listener = "5.3" serde = "1.0" line_drawing = { version = "1.0", optional = true } -kiddo = { version = "4.2" } seldom_singleton = "0.2.0" bevy_turborand = { version = "0.9.0", optional = true } seldom_map_nav = { version = "0.7.0", optional = true } diff --git a/src/image.rs b/src/image.rs index c6866a0..e597d96 100644 --- a/src/image.rs +++ b/src/image.rs @@ -56,6 +56,7 @@ impl PxImage

{ self.image.len() } + #[allow(unused)] pub(crate) fn iter_mut(&mut self) -> impl Iterator { self.image.iter_mut() } @@ -178,7 +179,7 @@ pub(crate) struct PxImageSliceMut<'a, P: Pixel> { slice: IRect, } -impl<'a, P: Pixel> PxImageSliceMut<'a, P> { +impl PxImageSliceMut<'_, P> { /// First `usize` is the index in the slice. Second `usize` is the index in the image. pub(crate) fn for_each_mut(&mut self, f: impl Fn(usize, usize, &mut P)) { let row_min = self.slice.min.x.clamp(0, self.width as i32) as usize; diff --git a/src/palette.rs b/src/palette.rs index 54038e3..f458550 100644 --- a/src/palette.rs +++ b/src/palette.rs @@ -144,6 +144,7 @@ static ASSET_PALETTE_INITIALIZED: AtomicBool = AtomicBool::new(false); /// Notifies after `ASSET_PALETTE_INITIALIZED` is set static ASSET_PALETTE_JUST_INITIALIZED: Event = Event::new(); +#[allow(static_mut_refs)] pub(crate) async fn asset_palette() -> &'static Palette { if ASSET_PALETTE_INITIALIZED.load(Ordering::SeqCst) { // SAFETY: Checked above @@ -159,7 +160,7 @@ pub(crate) async fn asset_palette() -> &'static Palette { just_initialized.await; // SAFETY: `just_initialized` finished waiting, so `ASSET_PALETTE_INITIALIZED` is set - return unsafe { ASSET_PALETTE.as_ref() }.unwrap(); + unsafe { ASSET_PALETTE.as_ref() }.unwrap() } fn load_asset_palette(palette: LoadingAssetPaletteParam, mut cmd: Commands) { diff --git a/src/particle.rs b/src/particle.rs index 18d5068..4d78edc 100644 --- a/src/particle.rs +++ b/src/particle.rs @@ -12,20 +12,19 @@ use crate::{position::PxLayer, prelude::*, set::PxSet}; const TIME_OFFSET: Duration = Duration::from_secs(60 * 60 * 24); pub(crate) fn plug(app: &mut App) { - app.configure_sets(PostUpdate, PxSet::UpdateEmitters.before(PxSet::Draw)) - .add_systems( - PostUpdate, + app.add_systems( + PostUpdate, + ( ( - ( - (simulate_emitters::, insert_emitter_time), - (apply_deferred, update_emitters::) - .chain() - .in_set(PxSet::UpdateEmitters), - ) - .chain(), - despawn_particles.before(PxSet::Draw), - ), - ); + (simulate_emitters::, insert_emitter_time), + (apply_deferred, update_emitters::) + .chain() + .in_set(PxSet::UpdateEmitters), + ) + .chain(), + despawn_particles, + ), + ); } /// Possible sprites for an emitter's particles diff --git a/src/screen.rs b/src/screen.rs index ad61c5b..bfeec2b 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -19,14 +19,12 @@ use bevy::{ TextureSampleType, TextureViewDescriptor, TextureViewDimension, VertexState, }, renderer::{RenderContext, RenderDevice, RenderQueue}, - texture::{BevyDefault, GpuImage, TextureFormatPixelInfo}, + texture::{BevyDefault, TextureFormatPixelInfo}, view::ViewTarget, Render, RenderApp, RenderSet, }, - tasks::{ComputeTaskPool, ParallelSliceMut}, window::{PrimaryWindow, WindowResized}, }; -use kiddo::ImmutableKdTree; #[cfg(feature = "line")] use crate::line::{draw_line, LineComponents}; @@ -40,10 +38,7 @@ use crate::{ palette::{PaletteHandle, PaletteParam}, position::PxLayer, prelude::*, - sprite::{ - dither_slice, ClosestAlg, Dither, DitherAlgorithm, ImageToSpriteComponents, OrderedAlg, - PatternAlg, SpriteComponents, ThresholdMap, - }, + sprite::SpriteComponents, text::TextComponents, }; @@ -137,7 +132,7 @@ pub struct Screen { pub(crate) computed_size: UVec2, window_aspect_ratio: f32, pub(crate) palette: [Vec3; 256], - pub(crate) palette_tree: ImmutableKdTree, + // pub(crate) palette_tree: ImmutableKdTree, } impl Screen { @@ -165,7 +160,7 @@ fn insert_screen(size: ScreenSize) -> impl Fn(Query<&Window, With computed_size: size.compute(Vec2::new(window.width(), window.height())), window_aspect_ratio: window.width() / window.height(), palette: [Vec3::ZERO; 256], - palette_tree: ImmutableKdTree::from(&[][..]), + // palette_tree: ImmutableKdTree::from(&[][..]), }); } } @@ -289,7 +284,7 @@ struct PxRender; struct PxRenderNode { maps: QueryState>, tiles: QueryState, - image_to_sprites: QueryState>, + // image_to_sprites: QueryState>, sprites: QueryState>, texts: QueryState>, #[cfg(feature = "line")] @@ -302,7 +297,7 @@ impl FromWorld for PxRenderNode { Self { maps: world.query(), tiles: world.query(), - image_to_sprites: world.query(), + // image_to_sprites: world.query(), sprites: world.query(), texts: world.query(), #[cfg(feature = "line")] @@ -318,7 +313,7 @@ impl ViewNode for PxRenderNode { fn update(&mut self, world: &mut World) { self.maps.update_archetypes(world); self.tiles.update_archetypes(world); - self.image_to_sprites.update_archetypes(world); + // self.image_to_sprites.update_archetypes(world); self.sprites.update_archetypes(world); self.texts.update_archetypes(world); #[cfg(feature = "line")] @@ -350,34 +345,23 @@ impl ViewNode for PxRenderNode { ); #[cfg(feature = "line")] - let mut layer_contents = BTreeMap::< - _, - ( - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - ), - >::default(); + let mut layer_contents = + BTreeMap::<_, (Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>)>::default(); #[cfg(not(feature = "line"))] let mut layer_contents = - BTreeMap::<_, (Vec<_>, Vec<_>, Vec<_>, Vec<_>, (), Vec<_>, (), Vec<_>)>::default(); + BTreeMap::<_, (Vec<_>, Vec<_>, Vec<_>, (), Vec<_>, (), Vec<_>)>::default(); for (map, tileset, position, layer, canvas, animation, filter) in self.maps.iter_manual(world) { - if let Some((maps, _, _, _, _, _, _, _)) = layer_contents.get_mut(layer) { + if let Some((maps, _, _, _, _, _, _)) = layer_contents.get_mut(layer) { maps.push((map, tileset, position, canvas, animation, filter)); } else { layer_contents.insert( layer.clone(), ( vec![(map, tileset, position, canvas, animation, filter)], - default(), + // default(), default(), default(), default(), @@ -389,38 +373,37 @@ impl ViewNode for PxRenderNode { } } - for (image, position, anchor, layer, canvas, filter) in - self.image_to_sprites.iter_manual(world) - { - if let Some((_, image_to_sprites, _, _, _, _, _, _)) = layer_contents.get_mut(layer) { - image_to_sprites.push((image, position, anchor, canvas, filter)); - } else { - layer_contents.insert( - layer.clone(), - ( - default(), - vec![(image, position, anchor, canvas, filter)], - default(), - default(), - default(), - default(), - default(), - default(), - ), - ); - } - } + // for (image, position, anchor, layer, canvas, filter) in + // self.image_to_sprites.iter_manual(world) + // { + // if let Some((_, image_to_sprites, _, _, _, _, _, _)) = layer_contents.get_mut(layer) { + // image_to_sprites.push((image, position, anchor, canvas, filter)); + // } else { + // layer_contents.insert( + // layer.clone(), + // ( + // default(), + // vec![(image, position, anchor, canvas, filter)], + // default(), + // default(), + // default(), + // default(), + // default(), + // default(), + // ), + // ); + // } + // } for (sprite, position, anchor, layer, canvas, animation, filter) in self.sprites.iter_manual(world) { - if let Some((_, _, sprites, _, _, _, _, _)) = layer_contents.get_mut(layer) { + if let Some((_, sprites, _, _, _, _, _)) = layer_contents.get_mut(layer) { sprites.push((sprite, position, anchor, canvas, animation, filter)); } else { layer_contents.insert( layer.clone(), ( - default(), default(), vec![(sprite, position, anchor, canvas, animation, filter)], default(), @@ -436,13 +419,12 @@ impl ViewNode for PxRenderNode { for (text, typeface, rect, alignment, layer, canvas, animation, filter) in self.texts.iter_manual(world) { - if let Some((_, _, _, texts, _, _, _, _)) = layer_contents.get_mut(layer) { + if let Some((_, _, texts, _, _, _, _)) = layer_contents.get_mut(layer) { texts.push((text, typeface, rect, alignment, canvas, animation, filter)); } else { layer_contents.insert( layer.clone(), ( - default(), default(), default(), vec![(text, typeface, rect, alignment, canvas, animation, filter)], @@ -470,7 +452,7 @@ impl ViewNode for PxRenderNode { } .into_iter() { - if let Some((_, _, _, _, clip_lines, _, over_lines, _)) = + if let Some((_, _, _, clip_lines, _, over_lines, _)) = layer_contents.get_mut(&layer) { if clip { clip_lines } else { over_lines } @@ -485,7 +467,6 @@ impl ViewNode for PxRenderNode { default(), default(), default(), - default(), lines, default(), default(), @@ -498,7 +479,6 @@ impl ViewNode for PxRenderNode { default(), default(), default(), - default(), lines, default(), ) @@ -522,7 +502,7 @@ impl ViewNode for PxRenderNode { } .into_iter() { - if let Some((_, _, _, _, _, clip_filters, _, over_filters)) = + if let Some((_, _, _, _, clip_filters, _, over_filters)) = layer_contents.get_mut(&layer) { if clip { clip_filters } else { over_filters }.push((filter, animation)); @@ -537,7 +517,6 @@ impl ViewNode for PxRenderNode { default(), default(), default(), - default(), filters, default(), default(), @@ -550,7 +529,6 @@ impl ViewNode for PxRenderNode { default(), default(), default(), - default(), filters, ) }, @@ -560,7 +538,7 @@ impl ViewNode for PxRenderNode { } let tilesets = world.resource::>(); - let images = world.resource::>(); + // let images = world.resource::>(); let sprite_assets = world.resource::>(); let typefaces = world.resource::>(); let filters = world.resource::>(); @@ -573,7 +551,7 @@ impl ViewNode for PxRenderNode { _, ( maps, - image_to_sprites, + // image_to_sprites, sprites, texts, clip_lines, @@ -631,141 +609,144 @@ impl ViewNode for PxRenderNode { } } - // TODO Use more helpers - // TODO Feature gate - // TODO Immediate function version - for (image, position, anchor, canvas, filter) in image_to_sprites { - // let palette = screen.palette - // .colors - // .iter() - // .map(|&color| Oklaba::from(Srgba::from_u8_array_no_alpha(color)).to_vec3()) - // .collect::>(); - - let palette_tree = ImmutableKdTree::from( - &screen - .palette - .iter() - .map(|&color| color.into()) - .collect::>()[..], - ); - - let dither = &image.dither; - let Some(image) = images.get(&image.image) else { - info!("temp"); - continue; - }; - - // TODO https://github.com/bevyengine/bevy/blob/v0.14.1/examples/app/headless_renderer.rs - let size = image.texture_descriptor.size; - let size = UVec2::new(size.width, size.height); - - let data = PxImage::empty_from_image(image); - - let mut sprite = PxSprite { - frame_size: data.area(), - data, - }; - - let mut pixels = image - .data - .chunks_exact(4) - .zip(sprite.data.iter_mut()) - .enumerate() - .collect::>(); - - pixels.par_chunk_map_mut(ComputeTaskPool::get(), 20, |_, pixels| { - use DitherAlgorithm::*; - use ThresholdMap::*; - - match *dither { - None => dither_slice::( - pixels, - 0., - size, - &screen.palette_tree, - &screen.palette, - ), - Some(Dither { - algorithm: Ordered, - threshold, - threshold_map: X2_2, - }) => dither_slice::( - pixels, - threshold, - size, - &screen.palette_tree, - &screen.palette, - ), - Some(Dither { - algorithm: Ordered, - threshold, - threshold_map: X4_4, - }) => dither_slice::( - pixels, - threshold, - size, - &screen.palette_tree, - &screen.palette, - ), - Some(Dither { - algorithm: Ordered, - threshold, - threshold_map: X8_8, - }) => dither_slice::( - pixels, - threshold, - size, - &screen.palette_tree, - &screen.palette, - ), - Some(Dither { - algorithm: Pattern, - threshold, - threshold_map: X2_2, - }) => dither_slice::( - pixels, - threshold, - size, - &screen.palette_tree, - &screen.palette, - ), - Some(Dither { - algorithm: Pattern, - threshold, - threshold_map: X4_4, - }) => dither_slice::( - pixels, - threshold, - size, - &screen.palette_tree, - &screen.palette, - ), - Some(Dither { - algorithm: Pattern, - threshold, - threshold_map: X8_8, - }) => dither_slice::( - pixels, - threshold, - size, - &screen.palette_tree, - &screen.palette, - ), - } - }); - - draw_spatial( - &sprite, - (), - &mut layer_image, - *position, - *anchor, - *canvas, - None, - filter.and_then(|filter| filters.get(filter)), - camera, - ); - } + // I was trying to make `ImageToSprite` work without 1-frame lag, but this + // fundamentally needs GPU readback or something bc you can't just get image data + // from a `GpuImage`. I think those represent images that're actually on the GPU. So + // here's where I left off with that. I don't need `ImageToSprite` at the moment, so + // this will be left incomplete until I need it, if I ever do. + + // // TODO Use more helpers + // // TODO Feature gate + // // TODO Immediate function version + // for (image, position, anchor, canvas, filter) in image_to_sprites { + // // let palette = screen.palette + // // .colors + // // .iter() + // // .map(|&color| Oklaba::from(Srgba::from_u8_array_no_alpha(color)).to_vec3()) + // // .collect::>(); + + // let palette_tree = ImmutableKdTree::from( + // &screen + // .palette + // .iter() + // .map(|&color| color.into()) + // .collect::>()[..], + // ); + + // let dither = &image.dither; + // let Some(image) = images.get(&image.image) else { + // continue; + // }; + + // // TODO https://github.com/bevyengine/bevy/blob/v0.14.1/examples/app/headless_renderer.rs + // let size = image.size; + // let data = PxImage::empty(size); + + // let mut sprite = PxSprite { + // frame_size: data.area(), + // data, + // }; + + // let mut pixels = image + // .data + // .chunks_exact(4) + // .zip(sprite.data.iter_mut()) + // .enumerate() + // .collect::>(); + + // pixels.par_chunk_map_mut(ComputeTaskPool::get(), 20, |_, pixels| { + // use DitherAlgorithm::*; + // use ThresholdMap::*; + + // match *dither { + // None => dither_slice::( + // pixels, + // 0., + // size, + // &screen.palette_tree, + // &screen.palette, + // ), + // Some(Dither { + // algorithm: Ordered, + // threshold, + // threshold_map: X2_2, + // }) => dither_slice::( + // pixels, + // threshold, + // size, + // &screen.palette_tree, + // &screen.palette, + // ), + // Some(Dither { + // algorithm: Ordered, + // threshold, + // threshold_map: X4_4, + // }) => dither_slice::( + // pixels, + // threshold, + // size, + // &screen.palette_tree, + // &screen.palette, + // ), + // Some(Dither { + // algorithm: Ordered, + // threshold, + // threshold_map: X8_8, + // }) => dither_slice::( + // pixels, + // threshold, + // size, + // &screen.palette_tree, + // &screen.palette, + // ), + // Some(Dither { + // algorithm: Pattern, + // threshold, + // threshold_map: X2_2, + // }) => dither_slice::( + // pixels, + // threshold, + // size, + // &screen.palette_tree, + // &screen.palette, + // ), + // Some(Dither { + // algorithm: Pattern, + // threshold, + // threshold_map: X4_4, + // }) => dither_slice::( + // pixels, + // threshold, + // size, + // &screen.palette_tree, + // &screen.palette, + // ), + // Some(Dither { + // algorithm: Pattern, + // threshold, + // threshold_map: X8_8, + // }) => dither_slice::( + // pixels, + // threshold, + // size, + // &screen.palette_tree, + // &screen.palette, + // ), + // } + // }); + + // draw_spatial( + // &sprite, + // (), + // &mut layer_image, + // *position, + // *anchor, + // *canvas, + // None, + // filter.and_then(|filter| filters.get(filter)), + // camera, + // ); + // } for (sprite, position, anchor, canvas, animation, filter) in sprites { let Some(sprite) = sprite_assets.get(sprite) else { diff --git a/src/sprite.rs b/src/sprite.rs index 381e197..aebe517 100644 --- a/src/sprite.rs +++ b/src/sprite.rs @@ -9,7 +9,6 @@ use bevy::{ Extract, RenderApp, }, }; -use kiddo::{ImmutableKdTree, SquaredEuclidean}; use serde::{Deserialize, Serialize}; use crate::{ @@ -28,7 +27,10 @@ pub(crate) fn plug(app: &mut App) { .sub_app_mut(RenderApp) .add_systems( ExtractSchedule, - (extract_sprites::, extract_image_to_sprites::), + ( + extract_sprites::, + // extract_image_to_sprites:: + ), ); } @@ -208,190 +210,190 @@ pub struct Dither { pub threshold_map: ThresholdMap, } -// TODO Example -/// Renders the contents of an image to a sprite every tick. The image is interpreted as -/// `Rgba8UnormSrgb`. -#[derive(Component, Clone, Default, Debug)] -pub struct ImageToSprite { - /// Image to render - pub image: Handle, - /// Dithering - pub dither: Option, -} - -/// Spawns a sprite generated from an [`Image`] -#[derive(Bundle, Debug, Default)] -pub struct ImageToSpriteBundle { - /// A [`Handle`] component - pub image: ImageToSprite, - /// A [`PxPosition`] component - pub position: PxPosition, - /// A [`PxAnchor`] component - pub anchor: PxAnchor, - /// A layer component - pub layer: L, - /// A [`PxCanvas`] component - pub canvas: PxCanvas, - /// A [`Visibility`] component - pub visibility: Visibility, - /// An [`InheritedVisibility`] component - pub inherited_visibility: InheritedVisibility, -} - -pub(crate) trait MapSize { - const WIDTH: usize; - const MAP: [usize; SIZE]; -} - -impl MapSize<1> for () { - const WIDTH: usize = 1; - const MAP: [usize; 1] = [0]; -} - -impl MapSize<4> for () { - const WIDTH: usize = 2; - #[rustfmt::skip] - const MAP: [usize; 4] = [ - 0, 2, - 3, 1, - ]; -} - -impl MapSize<16> for () { - const WIDTH: usize = 4; - #[rustfmt::skip] - const MAP: [usize; 16] = [ - 0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5, - ]; -} - -impl MapSize<64> for () { - const WIDTH: usize = 8; - #[rustfmt::skip] - const MAP: [usize; 64] = [ - 0, 48, 12, 60, 3, 51, 15, 63, - 32, 16, 44, 28, 35, 19, 47, 31, - 8, 56, 4, 52, 11, 59, 7, 55, - 40, 24, 36, 20, 43, 27, 39, 23, - 2, 50, 14, 62, 1, 49, 13, 61, - 34, 18, 46, 30, 33, 17, 45, 29, - 10, 58, 6, 54, 9, 57, 5, 53, - 42, 26, 38, 22, 41, 25, 37, 21, - ]; -} - -pub(crate) trait Algorithm { - fn compute( - color: Vec3, - threshold: Vec3, - threshold_index: usize, - candidates: &mut [usize; MAP_SIZE], - palette_tree: &ImmutableKdTree, - palette: &[Vec3], - ) -> u8; -} - -pub(crate) enum ClosestAlg {} - -impl Algorithm for ClosestAlg { - fn compute( - color: Vec3, - _: Vec3, - _: usize, - _: &mut [usize; MAP_SIZE], - palette_tree: &ImmutableKdTree, - _: &[Vec3], - ) -> u8 { - palette_tree - .approx_nearest_one::(&color.into()) - .item as usize as u8 - } -} - -pub(crate) enum OrderedAlg {} - -impl Algorithm for OrderedAlg { - fn compute( - color: Vec3, - threshold: Vec3, - threshold_index: usize, - _: &mut [usize; MAP_SIZE], - palette_tree: &ImmutableKdTree, - _: &[Vec3], - ) -> u8 { - palette_tree - .approx_nearest_one::( - &(color + threshold * (threshold_index as f32 / MAP_SIZE as f32 - 0.5)).into(), - ) - .item as u8 - } -} - -pub(crate) enum PatternAlg {} - -impl Algorithm for PatternAlg { - fn compute( - color: Vec3, - threshold: Vec3, - threshold_index: usize, - candidates: &mut [usize; MAP_SIZE], - palette_tree: &ImmutableKdTree, - palette: &[Vec3], - ) -> u8 { - let mut error = Vec3::ZERO; - for candidate_ref in &mut *candidates { - let sample = color + error * threshold; - let candidate = palette_tree - .approx_nearest_one::(&sample.into()) - .item as usize; - - *candidate_ref = candidate; - error += color - palette[candidate]; - } - - candidates.sort_unstable_by(|&candidate_1, &candidate_2| { - palette[candidate_1][0].total_cmp(&palette[candidate_2][0]) - }); - - candidates[threshold_index] as u8 - } -} - -pub(crate) fn dither_slice, const MAP_SIZE: usize>( - pixels: &mut [(usize, (&[u8], &mut Option))], - threshold: f32, - size: UVec2, - palette_tree: &ImmutableKdTree, - palette: &[Vec3], -) where - (): MapSize, -{ - let mut candidates = [0; MAP_SIZE]; - - for &mut (i, (color, ref mut pixel)) in pixels { - let i = i as u32; - let pos = UVec2::new(i % size.x, i / size.x); - - if color[3] == 0 { - **pixel = None; - continue; - } - - **pixel = Some(A::compute( - Oklaba::from(Srgba::rgb_u8(color[0], color[1], color[2])).to_vec3(), - Vec3::splat(threshold), - <() as MapSize>::MAP[pos.x as usize % <() as MapSize>::WIDTH - * <() as MapSize>::WIDTH - + pos.y as usize % <() as MapSize>::WIDTH], - &mut candidates, - palette_tree, - palette, - )); - } -} +// // TODO Example +// /// Renders the contents of an image to a sprite every tick. The image is interpreted as +// /// `Rgba8UnormSrgb`. +// #[derive(Component, Clone, Default, Debug)] +// pub struct ImageToSprite { +// /// Image to render +// pub image: Handle, +// /// Dithering +// pub dither: Option, +// } + +// /// Spawns a sprite generated from an [`Image`] +// #[derive(Bundle, Debug, Default)] +// pub struct ImageToSpriteBundle { +// /// A [`Handle`] component +// pub image: ImageToSprite, +// /// A [`PxPosition`] component +// pub position: PxPosition, +// /// A [`PxAnchor`] component +// pub anchor: PxAnchor, +// /// A layer component +// pub layer: L, +// /// A [`PxCanvas`] component +// pub canvas: PxCanvas, +// /// A [`Visibility`] component +// pub visibility: Visibility, +// /// An [`InheritedVisibility`] component +// pub inherited_visibility: InheritedVisibility, +// } + +// pub(crate) trait MapSize { +// const WIDTH: usize; +// const MAP: [usize; SIZE]; +// } +// +// impl MapSize<1> for () { +// const WIDTH: usize = 1; +// const MAP: [usize; 1] = [0]; +// } +// +// impl MapSize<4> for () { +// const WIDTH: usize = 2; +// #[rustfmt::skip] +// const MAP: [usize; 4] = [ +// 0, 2, +// 3, 1, +// ]; +// } +// +// impl MapSize<16> for () { +// const WIDTH: usize = 4; +// #[rustfmt::skip] +// const MAP: [usize; 16] = [ +// 0, 8, 2, 10, +// 12, 4, 14, 6, +// 3, 11, 1, 9, +// 15, 7, 13, 5, +// ]; +// } +// +// impl MapSize<64> for () { +// const WIDTH: usize = 8; +// #[rustfmt::skip] +// const MAP: [usize; 64] = [ +// 0, 48, 12, 60, 3, 51, 15, 63, +// 32, 16, 44, 28, 35, 19, 47, 31, +// 8, 56, 4, 52, 11, 59, 7, 55, +// 40, 24, 36, 20, 43, 27, 39, 23, +// 2, 50, 14, 62, 1, 49, 13, 61, +// 34, 18, 46, 30, 33, 17, 45, 29, +// 10, 58, 6, 54, 9, 57, 5, 53, +// 42, 26, 38, 22, 41, 25, 37, 21, +// ]; +// } +// +// pub(crate) trait Algorithm { +// fn compute( +// color: Vec3, +// threshold: Vec3, +// threshold_index: usize, +// candidates: &mut [usize; MAP_SIZE], +// palette_tree: &ImmutableKdTree, +// palette: &[Vec3], +// ) -> u8; +// } +// +// pub(crate) enum ClosestAlg {} +// +// impl Algorithm for ClosestAlg { +// fn compute( +// color: Vec3, +// _: Vec3, +// _: usize, +// _: &mut [usize; MAP_SIZE], +// palette_tree: &ImmutableKdTree, +// _: &[Vec3], +// ) -> u8 { +// palette_tree +// .approx_nearest_one::(&color.into()) +// .item as usize as u8 +// } +// } +// +// pub(crate) enum OrderedAlg {} +// +// impl Algorithm for OrderedAlg { +// fn compute( +// color: Vec3, +// threshold: Vec3, +// threshold_index: usize, +// _: &mut [usize; MAP_SIZE], +// palette_tree: &ImmutableKdTree, +// _: &[Vec3], +// ) -> u8 { +// palette_tree +// .approx_nearest_one::( +// &(color + threshold * (threshold_index as f32 / MAP_SIZE as f32 - 0.5)).into(), +// ) +// .item as u8 +// } +// } +// +// pub(crate) enum PatternAlg {} +// +// impl Algorithm for PatternAlg { +// fn compute( +// color: Vec3, +// threshold: Vec3, +// threshold_index: usize, +// candidates: &mut [usize; MAP_SIZE], +// palette_tree: &ImmutableKdTree, +// palette: &[Vec3], +// ) -> u8 { +// let mut error = Vec3::ZERO; +// for candidate_ref in &mut *candidates { +// let sample = color + error * threshold; +// let candidate = palette_tree +// .approx_nearest_one::(&sample.into()) +// .item as usize; +// +// *candidate_ref = candidate; +// error += color - palette[candidate]; +// } +// +// candidates.sort_unstable_by(|&candidate_1, &candidate_2| { +// palette[candidate_1][0].total_cmp(&palette[candidate_2][0]) +// }); +// +// candidates[threshold_index] as u8 +// } +// } +// +// pub(crate) fn dither_slice, const MAP_SIZE: usize>( +// pixels: &mut [(usize, (&[u8], &mut Option))], +// threshold: f32, +// size: UVec2, +// palette_tree: &ImmutableKdTree, +// palette: &[Vec3], +// ) where +// (): MapSize, +// { +// let mut candidates = [0; MAP_SIZE]; +// +// for &mut (i, (color, ref mut pixel)) in pixels { +// let i = i as u32; +// let pos = UVec2::new(i % size.x, i / size.x); +// +// if color[3] == 0 { +// **pixel = None; +// continue; +// } +// +// **pixel = Some(A::compute( +// Oklaba::from(Srgba::rgb_u8(color[0], color[1], color[2])).to_vec3(), +// Vec3::splat(threshold), +// <() as MapSize>::MAP[pos.x as usize % <() as MapSize>::WIDTH +// * <() as MapSize>::WIDTH +// + pos.y as usize % <() as MapSize>::WIDTH], +// &mut candidates, +// palette_tree, +// palette, +// )); +// } +// } pub(crate) type SpriteComponents = ( &'static Handle, @@ -424,36 +426,36 @@ fn extract_sprites( } } -pub(crate) type ImageToSpriteComponents = ( - &'static ImageToSprite, - &'static PxPosition, - &'static PxAnchor, - &'static L, - &'static PxCanvas, - Option<&'static Handle>, -); - -fn extract_image_to_sprites( - image_to_sprites: Extract, &InheritedVisibility)>>, - mut cmd: Commands, -) { - for ((image_to_sprite, &position, &anchor, layer, &canvas, filter), visibility) in - &image_to_sprites - { - if !visibility.get() { - continue; - } - - let mut image_to_sprite = cmd.spawn(( - image_to_sprite.clone(), - position, - anchor, - layer.clone(), - canvas, - )); - - if let Some(filter) = filter { - image_to_sprite.insert(filter.clone()); - } - } -} +// pub(crate) type ImageToSpriteComponents = ( +// &'static ImageToSprite, +// &'static PxPosition, +// &'static PxAnchor, +// &'static L, +// &'static PxCanvas, +// Option<&'static Handle>, +// ); +// +// fn extract_image_to_sprites( +// image_to_sprites: Extract, &InheritedVisibility)>>, +// mut cmd: Commands, +// ) { +// for ((image_to_sprite, &position, &anchor, layer, &canvas, filter), visibility) in +// &image_to_sprites +// { +// if !visibility.get() { +// continue; +// } +// +// let mut image_to_sprite = cmd.spawn(( +// image_to_sprite.clone(), +// position, +// anchor, +// layer.clone(), +// canvas, +// )); +// +// if let Some(filter) = filter { +// image_to_sprite.insert(filter.clone()); +// } +// } +// }