bevy_pixel_buffer 0.3.0

A library to draw pixels in bevy
Documentation
//! Adds integrations with [bevy_egui] and other [egui] types. This modules
//! requires the `egui` feature.

use bevy::{math::Vec2, prelude::*};
use bevy_egui::{
    egui::{self, Color32},
    EguiContext,
};

use crate::{
    pixel::Pixel,
    pixel_buffer::{Fill, FillKind, PixelBuffer, PixelBufferSize},
};

/// Component inserted by the [PixelBufferEguiPlugin]. Holds all the necesary
/// information to draw a egui image with the pixel buffer.
#[derive(Component, Clone, Copy, Debug)]
pub struct EguiTexture {
    /// Egui texture ID
    pub id: egui::TextureId,
    /// Natural Size of the texture
    pub size: egui::Vec2,
}

/// Plugin that adds a [EguiTexture] component to all pixel buffers and keeps them up to date
pub struct PixelBufferEguiPlugin;

impl Plugin for PixelBufferEguiPlugin {
    fn build(&self, app: &mut App) {
        app.add_stage_after(
            CoreStage::PreUpdate, // So EguiTexture updates after pixel buffer is done, but before user updates the frame
            "pixel_buffer_egui",
            SystemStage::single_threaded(),
        )
        .add_system_to_stage("pixel_buffer_egui", register_egui)
        .add_system_to_stage(
            "pixel_buffer_egui",
            update_egui_texture_size.after(register_egui),
        );
    }
}

#[allow(clippy::type_complexity)]
fn register_egui(
    mut commands: Commands,
    mut egui_ctx: ResMut<EguiContext>,
    pixel_buffer: Query<(Entity, &PixelBuffer, &Handle<Image>), Added<Handle<Image>>>,
) {
    for (entity, pb, image_handle) in pixel_buffer.iter() {
        let texture = EguiTexture {
            id: egui_ctx.add_image(image_handle.clone_weak()),
            size: pb.size.egui_texture_size(),
        };
        commands.entity(entity).insert(texture);
    }
}

fn update_egui_texture_size(
    mut pixel_buffer: Query<(&PixelBuffer, &mut EguiTexture), Changed<PixelBuffer>>,
) {
    for (pb, mut texture) in pixel_buffer.iter_mut() {
        texture.size = pb.size.egui_texture_size();
    }
}

/*

EGUI EXTENSIONS FOR OTHER TYPES IN THE CRATE

*/

impl PixelBufferSize {
    /// Gets the size of the texture for the pixel buffer
    pub fn egui_texture_size(&self) -> egui::Vec2 {
        let sz = self.screen_size();
        egui::Vec2::new(sz.x as f32, sz.y as f32)
    }
}

impl Fill {
    /// Updates the [Fill] component to a [egui::Vec2] size.
    pub fn update_egui(&mut self, evec2: egui::Vec2) {
        self.kind = FillKind::Custom(Vec2::new(evec2.x, evec2.y));
    }
}

impl From<bevy_egui::egui::Color32> for Pixel {
    fn from(c: bevy_egui::egui::Color32) -> Self {
        c.to_array().into()
    }
}

impl Pixel {
    /// Gets the color as the egui Color32 sRGB color type
    pub fn as_egui_color32(self) -> egui::Color32 {
        Color32::from_rgba_unmultiplied(self.r, self.g, self.b, self.a)
    }

    /// Get the color as the egui RGBA linear color type
    pub fn as_egui_rgba(self) -> egui::Rgba {
        egui::Rgba::from_rgba_unmultiplied(
            self.r as f32 / 255.0,
            self.g as f32 / 255.0,
            self.b as f32 / 255.0,
            self.a as f32 / 255.0,
        )
    }
}

impl crate::query::PixelBuffersItem<'_> {
    /// Update the [PixelBuffer::fill] to an egui area
    pub fn update_fill_egui(&mut self, available_size: egui::Vec2) {
        self.pixel_buffer.fill.update_egui(available_size);
    }

    /// Gets the [EguiTexture] component of the query item.
    ///
    /// This is a shorthand for `item.egui_texture.unwrap()`. The `unwrap` will
    /// only panic if the [PixelBufferEguiPlugin] is not enabled.
    ///
    /// # Panics
    /// If the entity did not have an [EguiTexture] component because the
    /// [PixelBufferEguiPlugin] was not added to the app.
    pub fn egui_texture(&self) -> &EguiTexture {
        self.egui_texture.unwrap()
    }
}

impl crate::query::PixelBuffersReadOnlyItem<'_> {
    /// Gets the [EguiTexture] component of the query item.
    ///
    /// This is a shorthand for `item.egui_texture.unwrap()`. The `unwrap` will
    /// only panic if the [PixelBufferEguiPlugin] is not enabled.
    ///
    /// # Panics
    /// If the entity did not have an [EguiTexture] component because the
    /// [PixelBufferEguiPlugin] was not added to the app.
    pub fn egui_texture(&self) -> &EguiTexture {
        self.egui_texture.unwrap()
    }
}

impl<'w, 's> crate::query::QueryPixelBuffer<'w, 's> {
    /// Update the [PixelBuffer::fill] to an egui area
    ///
    /// # Panics
    /// If there are none or more than one pixel buffers. This method is
    /// intented to be used when there's only one pixel buffer.
    pub fn update_fill_egui(&mut self, available_size: egui::Vec2) {
        self.query
            .single_mut()
            .pixel_buffer
            .fill
            .update_egui(available_size);
    }

    /// Get the [EguiTexture] component.
    ///
    /// # Panics
    /// - If there are none or more than one pixel buffers. This method is
    /// intented to be used when there's only one pixel buffer.
    ///
    /// - If the entity did not have an [EguiTexture] component because the
    /// [PixelBufferEguiPlugin] was not added to the app.
    pub fn egui_texture(&self) -> &EguiTexture {
        self.query.single().egui_texture.unwrap()
    }
}