mirage-engine 0.1.0

Mirage, an immediate-mode 3D engine for simple games on desktop and the browser
Documentation
//! What the draws the camera never reaches cost the frame.

use super::*;

/// Straight above the ground, over [`ACROSS`] meters of it, so a draw
/// further out than that is one the camera never covers.
const ABOVE: Camera = Camera::new(
    View::look_at(Vec3::new(0.0, 10.0, 0.0), Vec3::ZERO).with_up(Vec3::NEG_Z),
    Projection::orthographic(ACROSS),
);

/// A ground plane seen from above with cubes drawn over it: `seen` of
/// them where the camera looks, and `unseen` well outside it.
struct Extras {
    seen: u32,
    unseen: u32,
}

impl Game for Extras {
    type Meshes = GroundSet;
    type Sounds = NoSounds;
    type InputActions = NoInputActions;
    type Skyboxes = NoSkyboxes;
    type SurfaceStyles = ();
    type PostEffects = ();

    fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}

    fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
        ctx.set_camera(ABOVE);
        ctx.draw(
            Ground::Floor
                .at(Transform::from_scale(Vec3::splat(ACROSS)))
                .material(Material::color(Color::rgb(0.25, 0.25, 0.25))),
        );
        let standing = (0..self.seen)
            .map(|at| -3.0 + at as f32 * 2.0)
            .chain((0..self.unseen).map(|at| -8.0 - at as f32 * 2.0));
        for across in standing {
            ctx.draw(
                Ground::Blocker
                    .at(Vec3::new(across, 1.0, 0.0))
                    .material(Material::color(Color::WHITE)),
            );
        }
    }
}

/// The pixels one such scene reads back, and the instance count the
/// camera drew it in.
fn extras(seen: u32, unseen: u32) -> Option<(Vec<u8>, u32)> {
    let scene = Extras { seen, unseen };
    let mut session = Session::new(raw("headless culling"), UVec2::splat(YARD), |_ctx| {
        Ok(scene)
    })
    .ok()?;
    let stats = session.step();

    Some((
        session.pixels().expect("the target reads back"),
        stats.instances(),
    ))
}

#[test]
fn the_draws_the_camera_never_reaches_leave_the_frame_as_it_was_and_cost_no_instance() {
    let Some((bare, alone)) = extras(0, 0) else {
        eprintln!("skipped: this machine has no usable graphics adapter");
        return;
    };
    let (Some((hidden, culled)), Some((shown, drawn))) = (extras(0, 4), extras(4, 0)) else {
        return;
    };

    assert_eq!(hidden, bare, "what the camera never reaches leaves no mark");
    assert_eq!((alone, culled), (1, 1), "and is drawn in no instance");
    assert_ne!(shown, bare, "while what it reaches is drawn");
    assert_eq!(drawn, 5, "one instance each");
}