bevy_pixels 0.16.0

Bevy plugin that uses Pixels (a tiny pixel buffer) for rendering
Documentation
use bevy::{
    app::MainScheduleOrder,
    ecs::message::Messages,
    prelude::*,
    window::{PrimaryWindow, WindowBackendScaleFactorChanged, WindowResized},
};
use bevy_pixels::prelude::*;

#[derive(Resource, Default, Debug, PartialEq, Eq)]
struct ExecutionTrace(Vec<&'static str>);

#[derive(Resource, Default, Debug, PartialEq, Eq)]
struct ScheduleCounts {
    draw: u32,
    render: u32,
}

fn record_post_update(mut trace: ResMut<ExecutionTrace>) {
    trace.0.push("post_update");
}

fn record_draw(mut trace: ResMut<ExecutionTrace>) {
    trace.0.push("draw");
}

fn record_render(mut trace: ResMut<ExecutionTrace>) {
    trace.0.push("render");
}

fn record_last(mut trace: ResMut<ExecutionTrace>) {
    trace.0.push("last");
}

fn count_draw(mut counts: ResMut<ScheduleCounts>) {
    counts.draw += 1;
}

fn count_render(mut counts: ResMut<ScheduleCounts>) {
    counts.render += 1;
}

fn add_primary_window(app: &mut App) -> Entity {
    app.world_mut()
        .spawn((Window::default(), PrimaryWindow))
        .id()
}

#[test]
fn public_api_inserts_default_primary_window_options() {
    let mut app = App::new();
    let window = add_primary_window(&mut app);

    app.add_plugins(PixelsPlugin::default());

    assert_eq!(
        app.world().get::<PixelsOptions>(window),
        Some(&PixelsOptions::default())
    );
}

#[test]
fn public_api_inserts_custom_primary_window_options() {
    let mut app = App::new();
    let window = add_primary_window(&mut app);
    let options = PixelsOptions {
        width: 320,
        height: 240,
        scale_factor: 2.0,
        auto_resize_buffer: false,
        auto_resize_surface: false,
    };

    app.add_plugins(PixelsPlugin {
        primary_window: Some(options),
    });

    assert_eq!(app.world().get::<PixelsOptions>(window), Some(&options));
}

#[test]
fn only_primary_window_receives_auto_inserted_options() {
    let mut app = App::new();
    let primary = add_primary_window(&mut app);
    let secondary = app.world_mut().spawn(Window::default()).id();

    app.add_plugins(PixelsPlugin::default());

    assert_eq!(
        app.world().get::<PixelsOptions>(primary),
        Some(&PixelsOptions::default())
    );
    assert!(app.world().get::<PixelsOptions>(secondary).is_none());
}

#[test]
fn plugin_with_primary_window_none_updates_without_inserting_options() {
    let mut app = App::new();
    let window = add_primary_window(&mut app);

    app.add_plugins(PixelsPlugin {
        primary_window: None,
    });
    app.update();

    assert!(app.world().get::<PixelsOptions>(window).is_none());
}

#[test]
fn draw_and_render_schedules_run_in_expected_frame_order() {
    let mut app = App::new();
    app.init_resource::<ExecutionTrace>();
    app.add_plugins(PixelsPlugin {
        primary_window: None,
    });
    app.add_systems(PostUpdate, record_post_update);
    app.add_systems(Draw, record_draw);
    app.add_systems(Render, record_render);
    app.add_systems(Last, record_last);

    app.update();

    assert_eq!(
        app.world().resource::<ExecutionTrace>().0,
        vec!["post_update", "draw", "render", "last"]
    );
}

#[test]
fn draw_and_render_schedules_run_every_frame() {
    let mut app = App::new();
    app.init_resource::<ScheduleCounts>();
    app.add_plugins(PixelsPlugin {
        primary_window: None,
    });
    app.add_systems(Draw, count_draw);
    app.add_systems(Render, count_render);

    app.update();
    app.update();
    app.update();

    assert_eq!(
        *app.world().resource::<ScheduleCounts>(),
        ScheduleCounts { draw: 3, render: 3 }
    );
}

#[test]
fn public_schedule_order_resource_matches_custom_schedules() {
    let mut app = App::new();
    app.add_plugins(PixelsPlugin {
        primary_window: None,
    });

    let order = app.world().resource::<MainScheduleOrder>();
    let labels = &order.labels;
    let draw_index = labels
        .iter()
        .position(|label| (**label).eq(&Draw))
        .expect("draw schedule should exist");
    let render_index = labels
        .iter()
        .position(|label| (**label).eq(&Render))
        .expect("render schedule should exist");
    let post_update_index = labels
        .iter()
        .position(|label| (**label).eq(&PostUpdate))
        .expect("post update schedule should exist");
    let last_index = labels
        .iter()
        .position(|label| (**label).eq(&Last))
        .expect("last schedule should exist");

    assert_eq!(draw_index, post_update_index + 1);
    assert_eq!(render_index, draw_index + 1);
    assert!(render_index < last_index);
}

#[test]
fn plugin_registers_window_messages_for_public_apps() {
    let mut app = App::new();
    app.add_plugins(PixelsPlugin {
        primary_window: None,
    });

    assert!(app.world().contains_resource::<Messages<WindowResized>>());
    assert!(
        app.world()
            .contains_resource::<Messages<WindowBackendScaleFactorChanged>>()
    );
}