use crate::{
bundle::PixelBufferBundle,
pixel_buffer::{create_image, Fill, PixelBuffer, PixelBufferSize},
prelude::{Frame, FrameEditExtension, GetFrame},
};
use bevy::{ecs::system::EntityCommands, prelude::*, sprite::Anchor};
#[derive(Clone, Debug)]
pub enum RenderConfig {
Sprite {
spawn_camera: bool,
sprite_bundle: CustomSpriteBundle,
},
}
#[derive(Clone, Debug, Default)]
#[allow(missing_docs)]
pub struct CustomSpriteBundle {
pub sprite: CustomSprite,
pub transform: Transform,
pub global_transform: GlobalTransform,
pub visibility: Visibility,
pub inherited_visibility: InheritedVisibility,
pub view_visibility: ViewVisibility,
}
#[derive(Clone, Debug, Default)]
#[allow(missing_docs)]
pub struct CustomSprite {
pub color: Color,
pub flip_x: bool,
pub flip_y: bool,
pub anchor: Anchor,
}
impl Default for RenderConfig {
fn default() -> Self {
Self::sprite()
}
}
impl RenderConfig {
pub fn sprite_and_camera() -> Self {
Self::Sprite {
spawn_camera: true,
sprite_bundle: Default::default(),
}
}
pub fn sprite() -> Self {
Self::Sprite {
spawn_camera: false,
sprite_bundle: Default::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct RenderConfigBuilder(pub Option<RenderConfig>);
impl Default for RenderConfigBuilder {
fn default() -> Self {
Self(Some(RenderConfig::sprite_and_camera()))
}
}
impl From<bool> for RenderConfigBuilder {
fn from(v: bool) -> Self {
Self(if v {
Some(RenderConfig::sprite_and_camera())
} else {
None
})
}
}
impl From<Option<RenderConfig>> for RenderConfigBuilder {
fn from(v: Option<RenderConfig>) -> Self {
Self(v)
}
}
impl From<RenderConfig> for RenderConfigBuilder {
fn from(v: RenderConfig) -> Self {
Self(Some(v))
}
}
#[derive(Debug, Clone)]
pub struct PixelBufferBuilder {
pub size: PixelBufferSize,
pub fill: Fill,
pub render: Option<RenderConfig>,
}
impl Default for PixelBufferBuilder {
fn default() -> Self {
Self {
size: Default::default(),
fill: Default::default(),
render: Some(RenderConfig::sprite_and_camera()),
}
}
}
impl PixelBufferBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_size(mut self, size: impl Into<PixelBufferSize>) -> Self {
self.size = size.into();
self
}
pub fn with_fill(mut self, fill: impl Into<Fill>) -> Self {
self.fill = fill.into();
self
}
pub fn with_render(mut self, render: impl Into<RenderConfigBuilder>) -> Self {
self.render = render.into().0;
self
}
pub fn spawn<'a>(
self,
commands: &'a mut Commands,
images: &'a mut Assets<Image>,
) -> PixelBufferCommands<'a> {
let entity = commands.spawn(());
create_pixel_buffer(entity, images, self.size, self.fill, self.render)
}
pub fn insert<'a>(
self,
commands: &'a mut Commands,
images: &'a mut Assets<Image>,
entity: Entity,
) -> PixelBufferCommands<'a> {
let entity = commands.entity(entity);
create_pixel_buffer(entity, images, self.size, self.fill, self.render)
}
pub fn setup(self) -> impl FnMut(Commands, ResMut<Assets<Image>>) {
move |mut commands, mut images| {
self.clone().spawn(&mut commands, &mut images);
}
}
}
fn create_pixel_buffer<'a>(
mut entity: EntityCommands<'a>,
images: &'a mut Assets<Image>,
size: PixelBufferSize,
fill: Fill,
render: Option<RenderConfig>,
) -> PixelBufferCommands<'a> {
let image = images.add(create_image(size.size.into()));
if let Some(render) = render {
match render {
RenderConfig::Sprite {
spawn_camera,
sprite_bundle,
} => {
if spawn_camera {
entity.commands().spawn(Camera2dBundle::default());
}
let sprite_bundle = SpriteBundle {
sprite: Sprite {
custom_size: Some(size.screen_size().as_vec2()),
color: sprite_bundle.sprite.color,
flip_x: sprite_bundle.sprite.flip_x,
flip_y: sprite_bundle.sprite.flip_y,
anchor: sprite_bundle.sprite.anchor,
rect: None,
},
texture: image.clone(),
transform: sprite_bundle.transform,
global_transform: sprite_bundle.global_transform,
visibility: sprite_bundle.visibility,
inherited_visibility: sprite_bundle.inherited_visibility,
view_visibility: sprite_bundle.view_visibility,
};
entity.insert(sprite_bundle);
}
}
}
entity.insert(PixelBufferBundle {
pixel_buffer: PixelBuffer { size, fill },
image: image.clone(),
});
PixelBufferCommands {
images,
image_handle: image.clone_weak(),
entity_commands: entity,
}
}
pub fn pixel_buffer_setup(
size: impl Into<PixelBufferSize>,
) -> impl Fn(Commands, ResMut<Assets<Image>>) {
let size = size.into();
move |mut commands, mut images| {
PixelBufferBuilder::new()
.with_size(size)
.spawn(&mut commands, &mut images);
}
}
pub struct PixelBufferCommands<'a> {
images: &'a mut Assets<Image>,
image_handle: Handle<Image>,
entity_commands: EntityCommands<'a>,
}
impl<'a> PixelBufferCommands<'a> {
pub fn edit_frame(&mut self, f: impl Fn(&mut Frame)) -> &mut Self
where
Self: FrameEditExtension,
{
<Self as FrameEditExtension>::edit_frame(self, f);
self
}
pub fn image(&self) -> Handle<Image> {
self.image_handle.clone()
}
pub fn image_weak(&self) -> Handle<Image> {
self.image_handle.clone_weak()
}
pub fn entity(&mut self) -> &mut EntityCommands<'a> {
&mut self.entity_commands
}
}
impl<'a> GetFrame for PixelBufferCommands<'a> {
fn frame(&mut self) -> Frame<'_> {
Frame::extract(self.images, &self.image_handle)
}
}