use std::default::Default;
use std::marker::PhantomData;
use bevy::asset::RenderAssetUsages;
use bevy::prelude::{Assets, Commands, Component, Image, Query, Res, ResMut, Sprite, Transform};
use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat};
use image::imageops::{flip_horizontal, rotate180};
use image::ImageBuffer;
use crate::engine::{location::Int2D, state::State};
use crate::visualization::{
asset_handle_factory::AssetHandleFactoryResource,
simulation_descriptor::SimulationDescriptor,
wrappers::{ActiveState, SimulationRenderEntity},
};
pub trait BatchRender<S: State> {
fn get_pixel(&self, loc: &Int2D) -> [u8; 4];
fn get_dimensions(&self) -> (u32, u32);
fn get_layer(&self) -> f32;
fn texture(&self) -> Image {
let (width, height) = self.get_dimensions();
let image_buffer = ImageBuffer::from_fn(width, height, |x, y| {
let loc = Int2D {
x: x as i32,
y: y as i32,
};
let pixel = self.get_pixel(&loc);
image::Rgba(pixel)
});
let image_buffer = flip_horizontal(&image_buffer);
let image_buffer = rotate180(&image_buffer);
Image::new(
Extent3d {
width,
height,
..Default::default()
},
TextureDimension::D2,
image_buffer.into_raw(),
TextureFormat::Rgba8UnormSrgb,
RenderAssetUsages::RENDER_WORLD,
)
}
fn render(
&self,
sprite_render_factory: &mut AssetHandleFactoryResource,
commands: &mut Commands,
sim: &mut SimulationDescriptor,
) where
Self: 'static + Sized + Sync + Send,
{
let texture = self.texture();
let handle = sprite_render_factory.assets.add(texture);
let transform = Transform::from_xyz(sim.center_x - 0.5, sim.center_y, self.get_layer());
commands
.spawn((Sprite::from_image(handle), transform))
.insert(Marker::<Self> {
marker: PhantomData,
})
.insert(SimulationRenderEntity);
}
fn get_texture_from_state(state: &S) -> Image;
fn batch_render(
mut assets: ResMut<Assets<Image>>,
mut query: Query<(&Marker<Self>, &mut Sprite)>,
state_wrapper: Res<ActiveState<S>>,
) where
Self: 'static + Sized + Sync + Send,
{
let Ok((_marker, mut sprite)) = query.single_mut() else {
return;
};
let new_image =
Self::get_texture_from_state(&(*state_wrapper).0.lock().expect("error on lock"));
let new_asset = assets.add(new_image);
sprite.image = new_asset;
}
}
#[derive(Component)]
pub struct Marker<T> {
marker: PhantomData<T>,
}