diff --git a/src/hex_table.rs b/src/hex_table.rs index ba0be36..484cde0 100644 --- a/src/hex_table.rs +++ b/src/hex_table.rs @@ -1,3 +1,11 @@ +use crate::table::{IntoImage, Table}; +use bevy::asset::RenderAssetUsages; +use bevy::image::{BevyDefault, Image}; +use bevy::prelude::Color; +use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat}; +use std::slice::Iter; + +#[derive(Clone)] pub struct HexTable { default: T, pub(crate) data: Vec, @@ -44,20 +52,20 @@ impl HexTable { pub fn around(&self, x: usize, y: usize) -> Vec<&T> { let x = x as isize; let y = y as isize; - let around : Vec<(isize, isize)> = vec![ - (x, y + 1), - (x + 1, y + 1), + let around: Vec<(isize, isize)> = vec![ (x, y - 1), (x + 1, y - 1), (x - 1, y), (x + 1, y), + (x - 1, y + 1), + (x, y + 1), ]; around .iter() .filter(|(x, y)| { *x >= 0 - && *x <= self.dimensions.0 as isize + && *x < self.dimensions.0 as isize && *y >= 0 && *y < self.dimensions.1 as isize }) @@ -70,7 +78,10 @@ impl HexTable { } pub fn get_dim(&self, x: usize, y: usize) -> &T { - self.get(x + y * self.dimensions.0) + if self.to_index(x, y) == self.data.len() { + panic!("index out of bounds {x}:{y}"); + } + self.get(self.to_index(x, y)) } pub fn set(&mut self, index: usize, value: T) { @@ -78,6 +89,100 @@ impl HexTable { } pub fn set_dim(&mut self, x: usize, y: usize, value: T) { - self.set(x + y * self.dimensions.0, value); + self.set(self.to_index(x, y), value); + } + + pub fn get_offset_of_line(&self, index: usize) -> (f32, f32) { + self.get_offset_of(index % self.dimensions.0, index / self.dimensions.0) + } + + pub fn get_offset_of(&self, x: usize, y: usize) -> (f32, f32) { + let y_f = self.scale * y as f32 * VERTICAL_OFFSET; + let mut x_f = x as f32 * self.scale; + if y % 2 == 1 { + x_f += self.scale / 2.0; + } + (x_f, y_f) + } + + #[inline] + fn to_index(&self, x: usize, y: usize) -> usize { + x + y * self.dimensions.0 + } + + #[inline] + fn to_coordinates(&self, index: usize) -> (usize, usize) { + (index % self.dimensions.0, index / self.dimensions.0) + } + + #[inline] + pub fn get_on_square_table<'a>(&self, x: usize, y: usize, table: &'a Table) -> &'a T { + let coordinates = self.get_offset_of(x, y); + let coordinates = (coordinates.0 as usize, coordinates.1 as usize); + table.get_dim(coordinates.0, coordinates.1) + } +} + +impl IntoImage for HexTable { + fn get_image_data(&self) -> Image { + let side = (self.len as f32 * self.scale) as u32; + let mut image = Image::new_fill( + Extent3d { + width: side, + height: side, + depth_or_array_layers: 1, + }, + TextureDimension::D2, + &[0, 0, 0, 0], + TextureFormat::bevy_default(), + RenderAssetUsages::default(), + ); + + + self.data + .iter() + .zip(0..self.data.len()) + .filter(|(v, _)| **v) + .for_each(|(_, i)| { + let coords = self.get_offset_of_line(i); + let coords = (coords.0 as u32, coords.1 as u32); + image + .set_color_at(coords.0, coords.1, Color::WHITE) + .unwrap(); + }); + + image + } +} + +impl IntoImage for HexTable { + fn get_image_data(&self) -> Image { + let side = (self.len as f32 * self.scale) as u32; + let mut image = Image::new_fill( + Extent3d { + width: side, + height: side, + depth_or_array_layers: 1, + }, + TextureDimension::D2, + &[0, 0, 0, 0], + TextureFormat::bevy_default(), + RenderAssetUsages::default(), + ); + + + self.data + .iter() + .zip(0..self.data.len()) + .filter(|(v, _)| **v != 0 ) + .for_each(|(v, i)| { + let coords = self.get_offset_of_line(i); + let coords = (coords.0 as u32, coords.1 as u32); + image + .set_color_at(coords.0, coords.1, Color::srgb_u8(*v, *v, *v)) + .unwrap(); + }); + + image } } diff --git a/src/main.rs b/src/main.rs index 80dfe2a..17e39cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,9 @@ use rand_chacha::rand_core::SeedableRng; use seed_automation::SeedAutomation; use crate::subplate_automation::HexMatrixView; -const RECTANGLE_SIDE: f32 = 1250.0; +extern crate bevy; +const RECTANGLE_SIDE: f32 = 1000.0; +const WINDOW_SIDE: u32 = 1200; @@ -25,7 +27,7 @@ fn main() { .add_plugins(DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { title: "Automations".into(), - resolution: WindowResolution::new(RECTANGLE_SIDE as u32, RECTANGLE_SIDE as u32), + resolution: WindowResolution::new(WINDOW_SIDE, WINDOW_SIDE), ..default() }), ..default() @@ -85,6 +87,7 @@ struct SeededRng(ChaCha8Rng); #[cfg(test)] mod tests { use crate::table::Table; + use crate::hex_table::HexTable; #[test] fn around_1(){ @@ -126,4 +129,18 @@ mod tests { let around = table.around_line(24); assert_eq!(around.len(), 4); } + + #[test] + fn hex_table_1(){ + let mut table = HexTable::new(10, false, 4.0); + let coord = table.get_offset_of(9, 0); + assert_eq!(coord, (36.0, 0.0)); + } + + #[test] + fn hex_table_around_1(){ + let mut table = HexTable::new(10, false, 4.0); + let around = table.around(9, 0); + assert_eq!(around.len(), 3); + } } \ No newline at end of file diff --git a/src/plate_automation.rs b/src/plate_automation.rs index d03011e..e065758 100644 --- a/src/plate_automation.rs +++ b/src/plate_automation.rs @@ -22,19 +22,7 @@ pub fn update_automation_view( return; } let (sprite, automation) = query.iter().next().unwrap(); - let size = automation.world.side as u32; - let data = automation.world.get_image_data(); - let image = Image::new( - Extent3d { - width: size, - height: size, - depth_or_array_layers: 1, - }, - TextureDimension::D2, - data, - TextureFormat::bevy_default(), - RenderAssetUsages::default(), - ); + let image = automation.world.get_image_data(); images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); diff --git a/src/seed_automation.rs b/src/seed_automation.rs index fc31656..80b08f5 100644 --- a/src/seed_automation.rs +++ b/src/seed_automation.rs @@ -18,19 +18,8 @@ pub fn update_automation_view( } let (sprite, automation) = query.iter().next().unwrap(); - let size = automation.world.side as u32; - let data = automation.world.get_image_data(); - let image = Image::new( - Extent3d { - width: size, - height: size, - depth_or_array_layers: 1, - }, - TextureDimension::D2, - data, - TextureFormat::bevy_default(), - RenderAssetUsages::default(), - ); + let image = automation.world.get_image_data(); + images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); diff --git a/src/subplate_automation.rs b/src/subplate_automation.rs index 4a7bea7..b8390b9 100644 --- a/src/subplate_automation.rs +++ b/src/subplate_automation.rs @@ -1,11 +1,13 @@ -use crate::table::{IntoImage, Table}; use crate::hex_table::HexTable; +use crate::table::{IntoImage, Table}; use crate::SeededRng; -use bevy::asset::{Assets, RenderAssetUsages}; -use bevy::image::{BevyDefault, Image}; +use bevy::asset::Assets; +use bevy::image::Image; use bevy::input::ButtonInput; -use bevy::prelude::{Color, Commands, Component, Entity, KeyCode, Query, Res, ResMut, Sprite, Text, With}; -use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat}; +use bevy::prelude::{ + Commands, Component, Entity, KeyCode, Query, Res, ResMut, Single, Sprite, + With, +}; use bevy::tasks::futures_lite::StreamExt; use rand::RngExt; use rand_chacha::ChaCha8Rng; @@ -20,36 +22,20 @@ pub fn update_automation_view( return; } let (sprite, automation) = query.iter().next().unwrap(); - let size = automation.world.side as u32; - let data = automation.world.get_image_data(); - let image = Image::new( - Extent3d { - width: size, - height: size, - depth_or_array_layers: 1, - }, - TextureDimension::D2, - data, - TextureFormat::bevy_default(), - RenderAssetUsages::default(), - ); + let image = automation.world.get_image_data(); images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); } pub fn update_automation( - mut query: Query<(&mut SubPlateAutomation, Entity)>, - mut hex_query: Query<&HexMatrixBuild>, + query: Single<(&mut SubPlateAutomation, Entity)>, + hex_query: Single<&mut HexMatrixBuild>, mut seeded_rng: ResMut, keys: Res>, mut commands: Commands, ) { - if query.is_empty() { - return; - } - - let (mut automation, _entity) = query.iter_mut().next().unwrap(); + let (mut automation, _entity) = query.into_inner(); if keys.just_pressed(KeyCode::Space) || keys.all_pressed([KeyCode::Space, KeyCode::ShiftLeft]) { let random = &mut seeded_rng.0; @@ -73,7 +59,7 @@ pub fn update_automation( } if keys.just_pressed(KeyCode::KeyF) { - automation.calculate_front_lines(&mut commands, hex_query); + automation.calculate_front_lines(&mut commands, hex_query, &automation); } } @@ -111,7 +97,6 @@ impl SubPlateAutomation { self.world.set(index, color); } - } fn smooth(&mut self) { @@ -141,39 +126,65 @@ impl SubPlateAutomation { continue; } - self.world - .set(index, rng.random::()); + self.world.set(index, rng.random::()); break; } } - fn calculate_front_lines(&self, commands: &mut Commands, hex_query: Query<&HexMatrixBuild>) { + fn calculate_front_lines( + &self, + commands: &mut Commands, + mut hex_query: Single<&mut HexMatrixBuild>, + automation: &SubPlateAutomation, + ) { + let table = &mut hex_query.hex_matrix; + let mut table_copy = table.clone(); - let generator = &hex_query.iter().next().unwrap().hex_matrix; - let all_points = generator.calculate(); + let mut edge = (0_usize, 0_usize); + for x in 0..table.dimensions.0 { + for y in 0..table.dimensions.1 { + let color = *table.get_on_square_table(x, y, &automation.world); + table.set_dim(x, y, color); + } + } - let own_points = all_points.iter().map(|(x, y)| { - let x_table = *x as usize; - let y_table = *y as usize; + for x in 0..table.dimensions.0 { + for y in 0..table.dimensions.1 { + let color = table.get_dim(x, y); + if *color == 0 { continue; } + let around = table.around(x, y); + if around.iter().all(|x1| *x1 == around[0]) { + table_copy.set_dim(x, y, 0); + }else { + let new_color = (color).overflowing_add(128_u8).0; - (*self.world.get_dim(x_table, y_table), x, y) - }).filter(|(v, _, _)| { - *v != 0 - }); + table_copy.set_dim(x, y, new_color); + + } + } + } + hex_query.hex_matrix = table_copy; commands.spawn((HexMatrixRedrawRequest)); } fn calculate_subplates(&self, commands: &mut Commands) { - let mut list : HashMap> = HashMap::new(); - self.world.iter().zip(0..self.world.data.len()).for_each(|(world, index)| { - if list.contains_key(world) { - list.get_mut(world).unwrap().push(index); - } - else { - list.insert(world.clone(), vec![index]); - } - }); - println!("{:?}", list.iter().map(|(c, v)| (c.clone(), v.len())).collect::>()); + let mut list: HashMap> = HashMap::new(); + self.world + .iter() + .zip(0..self.world.data.len()) + .for_each(|(world, index)| { + if list.contains_key(world) { + list.get_mut(world).unwrap().push(index); + } else { + list.insert(world.clone(), vec![index]); + } + }); + println!( + "{:?}", + list.iter() + .map(|(c, v)| (c.clone(), v.len())) + .collect::>() + ); } } @@ -194,53 +205,30 @@ pub fn setup_hex_matrix( println!("Seed hex matrix"); - let resolution = automation.world.side / 4; + let resolution = automation.world.side / 2; - let generator = HexTable::new(resolution, true, 4.0); - let mut table = Table::new(false, automation.world.side); - generator.calculate().iter().for_each(|(x, y)| { - let x = *x as usize; - let y = *y as usize; + let hex_table = HexTable::new(resolution, 0, 2.0); - if *automation.world.get_dim(x, y) == 0 { - return; - } - - table.set_dim(x, y, true); - }); - - let data = table.get_image_data(); - let image = Image::new( - Extent3d { - width: table.side as u32, - height: table.side as u32, - depth_or_array_layers: 1, - }, - TextureDimension::D2, - data, - TextureFormat::bevy_default(), - RenderAssetUsages::default(), - ); + let image = hex_table.get_image_data(); let sprite = view_query.iter().next().unwrap(); - images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); - commands.spawn((HexMatrixBuild{ - points: table, - hex_matrix: generator, - })); + commands.spawn( + (HexMatrixBuild { + hex_matrix: hex_table, + }), + ); } - pub fn update_hex_matrix_view( - mut data_query: Query<&HexMatrixBuild>, + mut data_query: Single<&HexMatrixBuild>, mut request_query: Query>, mut view_query: Query<&Sprite, With>, mut commands: Commands, mut images: ResMut>, -){ +) { if request_query.is_empty() { return; } @@ -248,24 +236,11 @@ pub fn update_hex_matrix_view( let req = request_query.iter_mut().next().unwrap(); commands.entity(req).despawn(); println!("Update hex matrix view"); - let table = data_query.iter_mut().next().unwrap(); - let data = table.points.get_image_data(); - - let image = Image::new( - Extent3d { - width: table.points.side as u32, - height: table.points.side as u32, - depth_or_array_layers: 1, - }, - TextureDimension::D2, - data, - TextureFormat::bevy_default(), - RenderAssetUsages::default(), - ); + let table = data_query.into_inner(); + let image = table.hex_matrix.get_image_data(); let sprite = view_query.iter().next().unwrap(); - images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); } @@ -279,7 +254,6 @@ pub struct HexMatrixRedrawRequest; pub struct HexMatrixView; #[derive(Component)] -pub struct HexMatrixBuild{ - points: Table, - hex_matrix: HexTable -} \ No newline at end of file +pub struct HexMatrixBuild { + hex_matrix: HexTable, +} diff --git a/src/table.rs b/src/table.rs index 834030b..b237611 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,5 +1,7 @@ -use bevy::prelude::Color; use std::ops::{Index, IndexMut}; +use bevy::asset::RenderAssetUsages; +use bevy::prelude::*; +use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat}; pub struct Table { default: T, @@ -95,11 +97,11 @@ impl Into> for Table { } pub trait IntoImage { - fn get_image_data(&self) -> Vec; + fn get_image_data(&self) -> Image; } impl IntoImage for Table { - fn get_image_data(&self) -> Vec { + fn get_image_data(&self) -> Image { let mut data: Vec = vec![0; self.side * self.side * 4]; self.data .iter() @@ -113,11 +115,21 @@ impl IntoImage for Table { data[idx + 2] = value; data[idx + 3] = value; }); - data + Image::new( + Extent3d { + width: self.side as u32, + height: self.side as u32, + depth_or_array_layers: 1, + }, + TextureDimension::D2, + data, + TextureFormat::bevy_default(), + RenderAssetUsages::default(), + ) } } impl IntoImage for Table { - fn get_image_data(&self) -> Vec { + fn get_image_data(&self) -> Image { let mut data: Vec = vec![0; self.side * self.side * 4]; self.data .iter() @@ -130,12 +142,22 @@ impl IntoImage for Table { data[idx + 2] = (color.blue * 256.0) as u8; data[idx + 3] = (color.alpha * 256.0) as u8; }); - data + Image::new( + Extent3d { + width: self.side as u32, + height: self.side as u32, + depth_or_array_layers: 1, + }, + TextureDimension::D2, + data, + TextureFormat::bevy_default(), + RenderAssetUsages::default(), + ) } } impl IntoImage for Table { - fn get_image_data(&self) -> Vec { + fn get_image_data(&self) -> Image { let mut data: Vec = vec![0; self.side * self.side * 4]; self.data .iter() @@ -148,7 +170,18 @@ impl IntoImage for Table { data[idx + 2] = *color; data[idx + 3] = if *color != 0 { 255 } else { 0 }; }); - data + + Image::new( + Extent3d { + width: self.side as u32, + height: self.side as u32, + depth_or_array_layers: 1, + }, + TextureDimension::D2, + data, + TextureFormat::bevy_default(), + RenderAssetUsages::default(), + ) } }