Skip to main content

Vec2

Struct Vec2 

Source
#[repr(C)]
pub struct Vec2 { pub x: f32, pub y: f32, }
Expand description

A 2-dimensional vector.

Fields§

§x: f32§y: f32

Implementations§

Source§

impl Vec2

Source

pub const ZERO: Vec2

All zeroes.

Source

pub const ONE: Vec2

All ones.

Source

pub const NEG_ONE: Vec2

All negative ones.

Source

pub const MIN: Vec2

All f32::MIN.

Source

pub const MAX: Vec2

All f32::MAX.

Source

pub const NAN: Vec2

All f32::NAN.

Source

pub const INFINITY: Vec2

All f32::INFINITY.

Source

pub const NEG_INFINITY: Vec2

All f32::NEG_INFINITY.

Source

pub const X: Vec2

A unit vector pointing along the positive X axis.

Source

pub const Y: Vec2

A unit vector pointing along the positive Y axis.

Source

pub const NEG_X: Vec2

A unit vector pointing along the negative X axis.

Source

pub const NEG_Y: Vec2

A unit vector pointing along the negative Y axis.

Source

pub const AXES: [Vec2; 2]

The unit axes.

Source

pub const USES_CORE_SIMD: bool = false

Vec2 uses Rust Portable SIMD

Source

pub const USES_NEON: bool = false

Vec2 uses Arm NEON

Source

pub const USES_SCALAR_MATH: bool = true

Vec2 uses scalar math

Source

pub const USES_SSE2: bool = false

Vec2 uses Intel SSE2

Source

pub const USES_WASM_SIMD: bool = false

Vec2 uses WebAssembly 128-bit SIMD

Source

pub const USES_WASM32_SIMD: bool = false

👎Deprecated since 0.31.0:

Renamed to USES_WASM_SIMD

Source

pub const fn new(x: f32, y: f32) -> Vec2

Creates a new vector.

Examples found in repository?
examples/animation.rs (line 165)
165const BUTTERFLY_RADIUS: Vec2 = Vec2::new(1.8, 1.4);
More examples
Hide additional examples
examples/stress-preview.rs (line 560)
557fn push_face(vertices: &mut Vec<Vertex>, indices: &mut Vec<u32>, a: Vec3, b: Vec3, c: Vec3) {
558    let normal = (b - a).cross(c - a).normalize();
559    let uvs = [
560        Vec2::new(0.0, 1.0),
561        Vec2::new(0.5, 0.0),
562        Vec2::new(1.0, 1.0),
563    ];
564    let base = vertices.len() as u32;
565    for (point, uv) in [a, b, c].into_iter().zip(uvs) {
566        vertices.push(Vertex::new(point, normal, uv));
567    }
568    indices.extend([base, base + 1, base + 2]);
569}
examples/sprite-adventure.rs (line 488)
480    fn push_out(self, point: Vec2, radius: f32) -> Vec2 {
481        let delta = point - self.center;
482        let escape = self.half + Vec2::splat(radius) - delta.abs();
483
484        if escape.min_element() <= 0.0 {
485            point
486        } else if escape.x < escape.y {
487            let x = self.center.x + delta.x.signum() * (self.half.x + radius);
488            Vec2::new(x, point.y)
489        } else {
490            let z = self.center.y + delta.y.signum() * (self.half.y + radius);
491            Vec2::new(point.x, z)
492        }
493    }
494}
495
496/// A cave mouth's opening: where it is, and which way along `Z` the room
497/// it leads out of lies.
498#[derive(Clone, Copy)]
499struct Mouth {
500    at: Vec3,
501    room_side: f32,
502}
503
504impl Mouth {
505    /// True where `position` lies between the pillars and past the plane
506    /// in front of the opening — where the only two outcomes are stepping
507    /// through and being held.
508    fn holds(&self, position: Vec3) -> bool {
509        let plane = self.at.z + self.room_side * MOUTH_CROSSING_INSET;
510
511        (position.x - self.at.x).abs() < MOUTH_OPENING_HALF
512            && (plane - position.z) * self.room_side > 0.0
513    }
514
515    /// Position of each of the two pillars flanking the opening.
516    fn pillars(&self) -> impl Iterator<Item = Vec3> + Clone {
517        let at = self.at;
518
519        SIDES
520            .into_iter()
521            .map(move |side| at + Vec3::X * (side * MOUTH_PILLAR_OFFSET))
522    }
523
524    /// True when the camera looks into this mouth: it always lies on `+Z`
525    /// of the player, so the mouth whose room lies that way is the one seen
526    /// from the room's side, and the one to fill with a lintel and the dark
527    /// under it. The other is looked through from behind, and leaves its
528    /// opening clear for the room to show through.
529    fn looked_into(&self) -> bool {
530        self.room_side > 0.0
531    }
532}
533
534// ---------------------------------------------------------------------
535// The water style
536// ---------------------------------------------------------------------
537
538/// The pond's whole look, over the one value it reads: how far its ripple
539/// has traveled.
540#[derive(Default, ShaderValues)]
541struct Water {
542    time: f32,
543}
544
545impl SurfaceStyle for Water {
546    const PASS: DrawPass = DrawPass::Translucent;
547    const SURFACE: Option<&'static str> = Some(include_str!("sprite_adventure_water.wgsl"));
548}
549
550surface_styles! { enum Looks { Water } }
551
552// ---------------------------------------------------------------------
553// Meshes
554// ---------------------------------------------------------------------
555
556/// The player's current area; never both drawn in one frame.
557#[derive(Clone, Copy, PartialEq, Eq)]
558enum Area {
559    Overworld,
560    Cave,
561}
562
563/// The overworld's ground tile, its texture the only thing that separates a
564/// draw of it from another.
565#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
566struct Ground;
567
568impl Mesh for Ground {
569    fn build(&self, assets: &Assets) -> MeshData {
570        Plane
571            .build(assets)
572            .with_texture(assets.texture(GROUND_SHEET).pixelated())
573    }
574}
575
576/// The shoreline sprite laid over the pond's styled water, cutout so the
577/// water shows through its cleared middle.
578#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
579struct Shore;
580
581impl Mesh for Shore {
582    fn build(&self, assets: &Assets) -> MeshData {
583        Plane
584            .build(assets)
585            .with_texture(assets.texture(POND_SHEET).pixelated())
586            .with_material(Material::lit(Color::WHITE).cutout())
587    }
588}
589
590/// A crate prop, its texture drawn over a cube.
591#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
592struct Crate;
593
594impl Mesh for Crate {
595    fn build(&self, assets: &Assets) -> MeshData {
596        Cube.build(assets)
597            .with_texture(assets.texture(CRATE_TEXTURE).pixelated())
598    }
599}
600
601/// The well's rim.
602#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
603struct Well;
604
605impl Mesh for Well {
606    fn build(&self, assets: &Assets) -> MeshData {
607        Cube.build(assets)
608            .with_texture(assets.texture(WELL_SHEET).pixelated())
609    }
610}
611
612/// The well's mouth, laid flat over the rim's top face.
613#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
614struct WellMouth;
615
616impl Mesh for WellMouth {
617    fn build(&self, assets: &Assets) -> MeshData {
618        Plane
619            .build(assets)
620            .with_texture(assets.texture(WELL_SHEET).pixelated())
621    }
622}
623
624/// A stone box: the mouth's pillars and lintel.
625#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
626struct Stone;
627
628impl Mesh for Stone {
629    fn build(&self, assets: &Assets) -> MeshData {
630        Cube.build(assets)
631            .with_texture(assets.texture(STONE_SHEET).pixelated())
632    }
633}
634
635/// A bush sprite, cutout with its own relief.
636#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
637struct Bush;
638
639impl Mesh for Bush {
640    fn build(&self, assets: &Assets) -> MeshData {
641        Quad.build(assets)
642            .with_texture(assets.texture(BUSH_SPRITE).pixelated())
643            .with_relief(assets.relief(BUSH_RELIEF))
644            .with_material(Material::lit(Color::WHITE).cutout())
645    }
646}
647
648/// A rock sprite, cutout with its own relief.
649#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
650struct Rock;
651
652impl Mesh for Rock {
653    fn build(&self, assets: &Assets) -> MeshData {
654        Quad.build(assets)
655            .with_texture(assets.texture(ROCK_SPRITE).pixelated())
656            .with_relief(assets.relief(ROCK_RELIEF))
657            .with_material(Material::lit(Color::WHITE).cutout())
658    }
659}
660
661/// A torch's post sprite, cutout with its own relief.
662#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
663struct Torch;
664
665impl Mesh for Torch {
666    fn build(&self, assets: &Assets) -> MeshData {
667        Quad.build(assets)
668            .with_texture(assets.texture(TORCH_SPRITE).pixelated())
669            .with_relief(assets.relief(TORCH_RELIEF))
670            .with_material(Material::lit(Color::WHITE).cutout())
671    }
672}
673
674/// A torch's flame sprite, added over the dark rather than lit.
675#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
676struct Flame;
677
678impl Mesh for Flame {
679    fn build(&self, assets: &Assets) -> MeshData {
680        Quad.build(assets)
681            .with_texture(assets.texture(FLAME_SHEET).pixelated())
682            .with_material(Material::color(FLAME_TINT).additive())
683    }
684}
685
686/// The player's sprite, cutout with its own relief, its sheet shared
687/// with `examples/isometric-board.rs`.
688#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
689struct Walker;
690
691impl Mesh for Walker {
692    fn build(&self, assets: &Assets) -> MeshData {
693        Quad.build(assets)
694            .with_texture(assets.texture(WALKER_SHEET).pixelated())
695            .with_relief(assets.relief(WALKER_RELIEF))
696            .with_material(Material::lit(Color::WHITE).cutout())
697    }
698}
699
700/// The cave floor tile.
701#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
702struct CaveFloor;
703
704impl Mesh for CaveFloor {
705    fn build(&self, assets: &Assets) -> MeshData {
706        Plane
707            .build(assets)
708            .with_texture(assets.texture(CAVE_SHEET).pixelated())
709    }
710}
711
712/// The cave wall face.
713#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
714struct CaveWall;
715
716impl Mesh for CaveWall {
717    fn build(&self, assets: &Assets) -> MeshData {
718        Cube.build(assets)
719            .with_texture(assets.texture(CAVE_SHEET).pixelated())
720    }
721}
722
723/// The loaded door, drawn as its source authored it.
724#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
725struct Door;
726
727impl Mesh for Door {
728    fn build(&self, assets: &Assets) -> MeshData {
729        assets.mesh(DOOR_MESH)
730    }
731}
732
733/// The loaded gem, repainted whole per draw so its glow color shifts.
734#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
735struct Gem;
736
737impl Mesh for Gem {
738    fn build(&self, assets: &Assets) -> MeshData {
739        assets.mesh(GEM_MESH)
740    }
741}
742
743// Everything this game can draw: the meshes above, plus the styled water,
744// the dark filling a looked-into mouth's opening, and the door's own frame,
745// which draw the bare engine primitives Plane, Quad and Cube.
746meshes! {
747    enum Shape {
748        Ground, Shore, Crate, Well, WellMouth, Stone, Bush, Rock, Torch,
749        Flame, Walker, CaveFloor, CaveWall, Door, Gem, Plane, Quad, Cube,
750    }
751}
752
753/// The interact click and the gem's chime, shared with the other examples.
754#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
755enum Sound {
756    Interact,
757    Gem,
758}
759
760impl Sounds for Sound {
761    fn build(&self, assets: &Assets) -> SoundData {
762        match self {
763            Sound::Interact => assets.sound("click"),
764            Sound::Gem => assets.sound("win"),
765        }
766    }
767}
768
769// ---------------------------------------------------------------------
770// Input
771// ---------------------------------------------------------------------
772
773/// Player movement: `WASD`, arrows, or a stick — the strongest reading is
774/// kept.
775#[derive(InputAxis2Action, Clone, Copy, PartialEq)]
776enum Move {
777    Walk,
778}
779
780impl InputAxis2Action for Move {
781    fn bindings(&self) -> Vec<Axis2Binding> {
782        match self {
783            Move::Walk => vec![
784                Axis2Binding::from(ButtonAxis2 {
785                    left: Key::A,
786                    right: Key::D,
787                    down: Key::S,
788                    up: Key::W,
789                }),
790                Axis2Binding::from(ButtonAxis2 {
791                    left: Key::Left,
792                    right: Key::Right,
793                    down: Key::Down,
794                    up: Key::Up,
795                }),
796                Axis2Binding::stick(Stick::Left),
797            ],
798        }
799    }
800}
801
802/// The two verbs this game reads as an edge: interacting with the door, and
803/// a reset of the world to every saved key's fallback.
804#[derive(InputButtonAction, Clone, Copy, PartialEq)]
805enum Button {
806    Interact,
807    Reset,
808}
809
810impl InputButtonAction for Button {
811    fn bindings(&self) -> Vec<ButtonBinding> {
812        match self {
813            Button::Interact => vec![Key::E.into(), Pad::West.into()],
814            Button::Reset => vec![Key::R.into()],
815        }
816    }
817}
818
819struct Controls;
820
821impl InputActions for Controls {
822    type Button = Button;
823    type Axis = NoInputAxes;
824    type Axis2 = Move;
825}
826
827// ---------------------------------------------------------------------
828// Save data
829// ---------------------------------------------------------------------
830
831/// The player's last position, read at startup and saved on area
832/// transition and gem pickup.
833#[derive(Saves, Clone, Copy)]
834enum Position {
835    X,
836    Z,
837}
838
839impl SaveKey for Position {
840    type Value = f64;
841
842    fn fallback(&self) -> f64 {
843        match self {
844            Position::X => PLAYER_SPAWN.x as f64,
845            Position::Z => PLAYER_SPAWN.z as f64,
846        }
847    }
848}
849
850/// The area the player is in, and whether the gem is taken.
851#[derive(Saves, Clone, Copy)]
852enum Flag {
853    InCave,
854    GemTaken,
855}
856
857impl SaveKey for Flag {
858    type Value = bool;
859
860    fn fallback(&self) -> bool {
861        false
862    }
863}
864
865// ---------------------------------------------------------------------
866// The player's facing
867// ---------------------------------------------------------------------
868
869/// The player's last facing: also its row in the sheet, top to bottom.
870#[derive(Clone, Copy, PartialEq)]
871enum Facing {
872    Toward = 0,
873    Right = 1,
874    Away = 2,
875    Left = 3,
876}
877
878impl Facing {
879    /// The facing `heading` points in, favoring its larger axis; `None` at
880    /// rest, so the caller can keep the last facing.
881    fn from_heading(heading: Vec2) -> Option<Self> {
882        if heading == Vec2::ZERO {
883            return None;
884        }
885        Some(if heading.x.abs() > heading.y.abs() {
886            if heading.x > 0.0 {
887                Self::Right
888            } else {
889                Self::Left
890            }
891        } else if heading.y > 0.0 {
892            Self::Away
893        } else {
894            Self::Toward
895        })
896    }
897}
898
899// ---------------------------------------------------------------------
900// The game
901// ---------------------------------------------------------------------
902
903/// The ground tile at `col, row`: the path's dirt along [`PATH_COLUMN`],
904/// the verges that edge it, and a hashed grass variant everywhere else.
905fn ground_cell(col: i32, row: i32) -> Frame {
906    let (column, sheet_row) = match col - PATH_COLUMN {
907        0 => (PATH_DIRT + row.rem_euclid(2) as u32, PATH_ROW),
908        -1 => (PATH_WEST_VERGE, PATH_ROW),
909        1 => (PATH_EAST_VERGE, PATH_ROW),
910        _ => (
911            (col * 31 + row * 17).rem_euclid(GROUND_COLUMNS as i32) as u32,
912            GRASS_ROW,
913        ),
914    };
915
916    Sheet::new(UVec2::new(GROUND_COLUMNS, GROUND_ROWS)).cell_at(UVec2::new(column, sheet_row))
917}
918
919/// The stone sheet's plain masonry, laid `tiles` times across: the sampler
920/// wraps, so a window wider than the sheet repeats the course.
921fn masonry(tiles: f32) -> Frame {
922    let course = 1.0 / STONE_ROWS as f32;
923
924    Frame::rect(Vec2::new(0.0, 1.0 - course), Vec2::new(tiles, 1.0))
925}
926
927/// The wall or door's alpha `fraction` of the way from [`SOLID`] to
928/// [`GHOST_ALPHA`].
929fn ghost_alpha(fraction: f32) -> f32 {
930    SOLID + (GHOST_ALPHA - SOLID) * fraction
931}
932
933/// The wall face in column `variant`, windowed to the meters `standing` of
934/// one course, measured up from that course's own base: every row of the
935/// cave sheet below the floor's covers [`WALL_HEIGHT`], so a course keeps
936/// the floor's texels to the meter however it is cut.
937fn cave_wall_face(variant: u32, standing: Range<f32>) -> Frame {
938    let cell = Vec2::new(1.0 / CAVE_COLUMNS as f32, 1.0 / CAVE_ROWS as f32);
939    let left = (variant % CAVE_COLUMNS) as f32 * cell.x;
940    let face = (CAVE_FLOOR_ROW + 1) as f32 * cell.y;
941    let up_from_base = |height: f32| 1.0 - (1.0 - face) * (height / WALL_HEIGHT);
942
943    Frame::rect(
944        Vec2::new(left, up_from_base(standing.end)),
945        Vec2::new(left + cell.x, up_from_base(standing.start)),
946    )
947}
948
949/// The logical point egui paints the physical pixel `pixel` at.
950fn logical(pixel: Vec2, pixels_per_point: f32) -> egui::Pos2 {
951    let point = pixel / pixels_per_point;
952    egui::pos2(point.x, point.y)
953}
954
955fn main() {
956    run(
957        Config::new("Mirage: sprite adventure")
958            .with_size(1280, 720)
959            .with_assets([
960                MODEL,
961                WALKER_SOURCE,
962                WALKER_RELIEF_SOURCE,
963                GROUND_SOURCE,
964                BUSH_SOURCE,
965                BUSH_RELIEF_SOURCE,
966                ROCK_SOURCE,
967                ROCK_RELIEF_SOURCE,
968                TORCH_RELIEF_SOURCE,
969                CRATE_SOURCE,
970                WELL_SOURCE,
971                STONE_SOURCE,
972                CAVE_SOURCE,
973                POND_SOURCE,
974                TORCH_SOURCE,
975                FLAME_SOURCE,
976                INTERACT_SOUND,
977                GEM_SOUND,
978            ]),
979        Keep::init,
980    );
981}
982
983struct Keep {
984    area: Area,
985    position: Vec3,
986    previous: Vec3,
987    facing: Facing,
988    walk_ticks: u32,
989    simulated: Duration,
990    door_opening: bool,
991    /// Ticks the door has been opening for, at a cap of
992    /// [`DOOR_SWING_TICKS`]: how long its world prompt reads "opening" once
993    /// it starts.
994    swing_ticks: u32,
995    gem_taken: bool,
996    /// How far the door wall's fade from [`SOLID`] to [`GHOST_ALPHA`] has
997    /// run as of the last tick: `0.0` to `1.0`.
998    ghost: f32,
999    /// Set by the panel's reset button, since its click lands in a frame
1000    /// rather than a tick; read and cleared on the next tick.
1001    reset_requested: bool,
1002}
1003
1004impl Keep {
1005    /// Prepares every startup-cataloged mesh and resumes wherever the last
1006    /// run left the player.
1007    fn init(ctx: &mut InitContext<'_, Keep>) -> Result<Self, Error> {
1008        let startup = ctx.startup();
1009        let gem_taken = startup.saved(Flag::GemTaken);
1010        let area = if startup.saved(Flag::InCave) {
1011            Area::Cave
1012        } else {
1013            Area::Overworld
1014        };
1015        let position = Vec3::new(
1016            startup.saved(Position::X) as f32,
1017            0.0,
1018            startup.saved(Position::Z) as f32,
1019        );
1020
1021        Ok(Self {
1022            area,
1023            position,
1024            previous: position,
1025            facing: Facing::Toward,
1026            walk_ticks: 0,
1027            simulated: Duration::ZERO,
1028            door_opening: gem_taken,
1029            swing_ticks: if gem_taken { DOOR_SWING_TICKS } else { 0 },
1030            gem_taken,
1031            ghost: 0.0,
1032            reset_requested: false,
1033        })
1034    }
1035
1036    fn camera(position: Vec3, offset: Vec3) -> Camera {
1037        Camera::new(
1038            View::look_at(position + offset, position),
1039            Projection::perspective(CAMERA_FOV),
1040        )
1041    }
1042
1043    /// Obstacles from the overworld's props: the crates, turned as they are
1044    /// drawn, the well's rim, the open water the shoreline rings, the
1045    /// mouth's pillars, and each flora's base.
1046    fn overworld_obstacles() -> impl Iterator<Item = Obstacle> + Clone {
1047        CRATE_POSITIONS
1048            .into_iter()
1049            .map(|(x, z, turn)| {
1050                Obstacle::footprint(Vec2::new(x, z), Vec2::splat(CRATE_SIZE * turned_span(turn)))
1051            })
1052            .chain([
1053                Obstacle::footprint(WELL_POSITION.xz(), WELL_SIZE.xz()),
1054                Obstacle::footprint(POND_CENTER.xz(), Vec2::splat(POND_WATER_HALF * 2.0)),
1055            ])
1056            .chain(
1057                ENTRANCE
1058                    .pillars()
1059                    .map(|at| Obstacle::footprint(at.xz(), MOUTH_PILLAR_SIZE.xz())),
1060            )
1061            .chain(FLORA.into_iter().map(|(x, z, rock)| {
1062                let base = if rock { ROCK_FOOTPRINT } else { BUSH_FOOTPRINT };
1063                Obstacle::footprint(Vec2::new(x, z), Vec2::splat(base))
1064            }))
1065    }
1066
1067    /// Obstacles from the cave: the torch posts, its own mouth's pillars,
1068    /// the runs of wall either side of the doorway and of the mouth, and the
1069    /// `door` leaf.
1070    fn cave_obstacles(door: Obstacle) -> impl Iterator<Item = Obstacle> + Clone {
1071        TORCH_POSITIONS
1072            .into_iter()
1073            .map(|(x, z)| Obstacle::footprint(Vec2::new(x, z), Vec2::splat(TORCH_STAND_WIDTH)))
1074            .chain(
1075                EXIT.pillars()
1076                    .map(|at| Obstacle::footprint(at.xz(), MOUTH_PILLAR_SIZE.xz())),
1077            )
1078            .chain(SIDES.into_iter().flat_map(|side| {
1079                [
1080                    Self::wall_run(side, DOOR_Z),
1081                    Self::wall_run(side, CAVE_LIP_Z),
1082                ]
1083            }))
1084            .chain([door])
1085    }
1086
1087    /// One of the two runs of wall either side of a one-tile opening on the
1088    /// room's axis, at `z`.
1089    fn wall_run(side: f32, z: f32) -> Obstacle {
1090        Obstacle::footprint(
1091            Vec2::new(side * (DOORWAY_HALF + DOOR_WALL_END) * 0.5, z),
1092            Vec2::new(DOOR_WALL_END - DOORWAY_HALF, TILE_SIZE),
1093        )
1094    }
1095
1096    /// Obstacle from the door leaf's own footprint: the box over its four
1097    /// corners, swung back against the wall once the door is opened.
1098    fn door_obstacle(&self) -> Obstacle {
1099        let hinge = DOOR_HINGE.xz();
1100        let across = DOOR_THICKNESS * 0.5;
1101        let corner = |along: f32, aside: f32| {
1102            let (x, z) = if self.door_opening {
1103                (aside, -along)
1104            } else {
1105                (along, aside)
1106            };
1107            hinge + Vec3::new(x, 0.0, z).xz()
1108        };
1109
1110        Obstacle::over([
1111            corner(0.0, -across),
1112            corner(0.0, across),
1113            corner(DOOR_WIDTH, -across),
1114            corner(DOOR_WIDTH, across),
1115        ])
1116    }
1117
1118    /// Pushes the player out of every obstacle their circle has walked into,
1119    /// over as many passes as it takes for one to leave them where the last
1120    /// one did — overlapping obstacles need more than one.
1121    fn push_out_of(&mut self, obstacles: impl Iterator<Item = Obstacle> + Clone) {
1122        /// Passes an overlap is given to settle before the frame takes what
1123        /// it has; ones this game builds settle in two.
1124        const PASSES: u32 = 4;
1125
1126        let mut standing = self.position.xz();
1127        for _ in 0..PASSES {
1128            let settled = obstacles.clone().fold(standing, |point, obstacle| {
1129                obstacle.push_out(point, PLAYER_RADIUS)
1130            });
1131            if settled == standing {
1132                break;
1133            }
1134            standing = settled;
1135        }
1136
1137        self.position.x = standing.x;
1138        self.position.z = standing.y;
1139    }
1140
1141    fn tick_overworld(&mut self, ctx: &mut TickContext<'_, Keep>) {
1142        self.push_out_of(Self::overworld_obstacles());
1143        self.position.x = self.position.x.clamp(-CLEARING_HALF, CLEARING_HALF);
1144        self.position.z = self.position.z.clamp(-CLEARING_HALF, CLEARING_HALF);
1145
1146        if ENTRANCE.holds(self.position) {
1147            if ENTRANCE.holds(self.previous) {
1148                self.position.z = self.previous.z;
1149            } else {
1150                self.enter_cave(ctx);
1151            }
1152        }
1153    }
1154
1155    fn tick_cave(&mut self, ctx: &mut TickContext<'_, Keep>) {
1156        self.push_out_of(Self::cave_obstacles(self.door_obstacle()));
1157        self.position.x = self.position.x.clamp(-CAVE_HALF_WIDTH, CAVE_HALF_WIDTH);
1158        self.position.z = self.position.z.clamp(CAVE_WALK_FAR_Z, CAVE_WALK_NEAR_Z);
1159
1160        let target = if self.position.z < DOOR_WALL_NEAR_Z {
1161            1.0
1162        } else {
1163            0.0
1164        };
1165        let step = 1.0 / GHOST_RAMP_TICKS as f32;
1166        self.ghost += (target - self.ghost).clamp(-step, step);
1167
1168        if !self.door_opening
1169            && ctx.pressed(Button::Interact)
1170            && self.position.distance(INTERACT_POINT) < INTERACT_RADIUS
1171        {
1172            self.door_opening = true;
1173            self.swing_ticks = 0;
1174            ctx.play(Sound::Interact);
1175        }
1176        if self.door_opening && self.swing_ticks < DOOR_SWING_TICKS {
1177            self.swing_ticks += 1;
1178        }
1179
1180        if !self.gem_taken && self.position.distance(GEM_POSITION) < PICKUP_RADIUS {
1181            self.gem_taken = true;
1182            ctx.play(Sound::Gem);
1183            ctx.save(Flag::GemTaken, true);
1184            ctx.save(Position::X, self.position.x as f64);
1185            ctx.save(Position::Z, self.position.z as f64);
1186        }
1187
1188        if EXIT.holds(self.position) {
1189            if EXIT.holds(self.previous) {
1190                self.position.z = self.previous.z;
1191            } else {
1192                self.exit_cave(ctx);
1193            }
1194        }
1195    }
1196
1197    /// Puts the player back at [`PLAYER_SPAWN`] with the cave and the gem
1198    /// returned to their saved fallbacks, all in this tick: a reset saves
1199    /// every key's own fallback, since there is nothing to clear it to.
1200    fn reset(&mut self, ctx: &mut TickContext<'_, Keep>) {
1201        ctx.save(Position::X, Position::X.fallback());
1202        ctx.save(Position::Z, Position::Z.fallback());
1203        ctx.save(Flag::InCave, Flag::InCave.fallback());
1204        ctx.save(Flag::GemTaken, Flag::GemTaken.fallback());
1205
1206        self.area = Area::Overworld;
1207        self.position = PLAYER_SPAWN;
1208        self.previous = PLAYER_SPAWN;
1209        self.gem_taken = false;
1210        self.door_opening = false;
1211        self.swing_ticks = 0;
1212        self.ghost = 0.0;
1213    }
1214
1215    /// Steps into the cave at [`CAVE_SPAWN`], saving the transition.
1216    fn enter_cave(&mut self, ctx: &mut TickContext<'_, Keep>) {
1217        self.area = Area::Cave;
1218        self.position = CAVE_SPAWN;
1219        self.previous = CAVE_SPAWN;
1220        ctx.save(Flag::InCave, true);
1221        ctx.save(Position::X, CAVE_SPAWN.x as f64);
1222        ctx.save(Position::Z, CAVE_SPAWN.z as f64);
1223    }
1224
1225    /// Steps back out to the mouth at [`RETURN_SPAWN`], saving the
1226    /// transition.
1227    fn exit_cave(&mut self, ctx: &mut TickContext<'_, Keep>) {
1228        self.area = Area::Overworld;
1229        self.position = RETURN_SPAWN;
1230        self.previous = RETURN_SPAWN;
1231        ctx.save(Flag::InCave, false);
1232        ctx.save(Position::X, RETURN_SPAWN.x as f64);
1233        ctx.save(Position::Z, RETURN_SPAWN.z as f64);
1234    }
1235
1236    fn draw_ground(&self, ctx: &mut FrameContext<'_, Keep>) {
1237        for col in -GROUND_DRAW_HALF..=GROUND_DRAW_HALF {
1238            for row in -GROUND_DRAW_HALF..=GROUND_DRAW_HALF {
1239                ctx.draw(
1240                    Ground
1241                        .at(Vec3::new(
1242                            col as f32 * TILE_SIZE,
1243                            0.0,
1244                            row as f32 * TILE_SIZE,
1245                        ))
1246                        .frame(ground_cell(col, row)),
1247                );
1248            }
1249        }
1250    }
1251
1252    /// Two staggered rows of bushes around the clearing, open where the path
1253    /// leaves it, drawn between the camera and the ground's edge. The rows
1254    /// running along `Z` skip their two ends, which the rows running along
1255    /// `X` already cover.
1256    fn draw_hedgerow(&self, ctx: &mut FrameContext<'_, Keep>) {
1257        for (row, half) in [HEDGE_INNER_HALF, HEDGE_OUTER_HALF].into_iter().enumerate() {
1258            let row = row as i32;
1259            // The inner row covers both corners; the outer one is half a
1260            // span in from each, backing the gaps the inner row leaves.
1261            let spans = ((2.0 * half / HEDGE_STEP).round() as i32).max(1);
1262            let span = 2.0 * half / spans as f32;
1263            let steps = spans - row;
1264            for step in 0..=steps {
1265                let along = -half + (step as f32 + 0.5 * row as f32) * span;
1266                let scale = if (step + row) % 2 == 0 { 1.0 } else { 0.8 };
1267                let (width, height) = (BUSH_WIDTH * scale, BUSH_HEIGHT * scale);
1268                // The path leaves through the rows running along `X`, so only
1269                // those two open around it.
1270                let gated = along.abs() < HEDGE_GATE_HALF;
1271                let corner = step == 0 || step == steps;
1272                let places = [
1273                    (along, -half, gated),
1274                    (along, half, gated),
1275                    (-half, along, corner),
1276                    (half, along, corner),
1277                ];
1278                for (x, z, skip) in places {
1279                    if skip {
1280                        continue;
1281                    }
1282                    ctx.draw(
1283                        Bush.at(Transform::from_scale_rotation_translation(
1284                            Vec3::new(width, height, width),
1285                            Quat::IDENTITY,
1286                            Vec3::new(x, height * 0.5, z),
1287                        ))
1288                        .upright(),
1289                    );
1290                }
1291            }
1292        }
1293    }
1294
1295    /// The pond: a square of styled water, and the shoreline sprite laid over
1296    /// it, which rings the open middle and hides the water's own edges.
1297    fn draw_pond(&self, ctx: &mut FrameContext<'_, Keep>) {
1298        ctx.draw(
1299            Plane
1300                .at(Transform::from_scale_rotation_translation(
1301                    Vec3::splat(POND_WATER_HALF * 2.0),
1302                    Quat::IDENTITY,
1303                    POND_CENTER,
1304                ))
1305                .material(Material::shaded(WATER_COLOR, WATER_LITNESS))
1306                .surface_style::<Water>(),
1307        );
1308        ctx.draw(
1309            Shore
1310                .at(Transform::from_scale_rotation_translation(
1311                    Vec3::splat(POND_HALF * 2.0),
1312                    Quat::IDENTITY,
1313                    Vec3::new(POND_CENTER.x, 0.0, POND_CENTER.z),
1314                ))
1315                .frame(Sheet::new(UVec2::new(POND_CELLS, 1)).cell(POND_SHORE_CELL)),
1316        );
1317    }
1318
1319    fn draw_crates(&self, ctx: &mut FrameContext<'_, Keep>) {
1320        for &(x, z, turn) in &CRATE_POSITIONS {
1321            ctx.draw(Crate.at(Transform::from_scale_rotation_translation(
1322                Vec3::splat(CRATE_SIZE),
1323                Quat::from_rotation_y(turn),
1324                Vec3::new(x, CRATE_SIZE * 0.5, z),
1325            )));
1326        }
1327    }
1328
1329    /// The well: its rim in grey masonry, and the mouth cell laid over the
1330    /// rim's top face.
1331    fn draw_well(&self, ctx: &mut FrameContext<'_, Keep>) {
1332        let cells = Sheet::new(UVec2::new(WELL_CELLS, 1));
1333        ctx.draw(
1334            Well.at(Transform::from_scale_rotation_translation(
1335                WELL_SIZE,
1336                Quat::IDENTITY,
1337                WELL_POSITION + Vec3::Y * (WELL_SIZE.y * 0.5),
1338            ))
1339            .frame(cells.cell(WELL_RIM_CELL)),
1340        );
1341        ctx.draw(
1342            WellMouth
1343                .at(Transform::from_scale_rotation_translation(
1344                    Vec3::new(WELL_SIZE.x, 1.0, WELL_SIZE.z),
1345                    Quat::IDENTITY,
1346                    WELL_POSITION + Vec3::Y * (WELL_SIZE.y + WELL_MOUTH_LIFT),
1347                ))
1348                .frame(cells.cell(WELL_MOUTH_CELL)),
1349        );
1350    }
1351
1352    fn draw_flora(&self, ctx: &mut FrameContext<'_, Keep>) {
1353        for &(x, z, rock) in &FLORA {
1354            let (width, height) = if rock {
1355                (ROCK_WIDTH, ROCK_HEIGHT)
1356            } else {
1357                (BUSH_WIDTH, BUSH_HEIGHT)
1358            };
1359            let standing = Transform::from_scale_rotation_translation(
1360                Vec3::new(width, height, width),
1361                Quat::IDENTITY,
1362                Vec3::new(x, height * 0.5, z),
1363            );
1364            let flora: Instance<Shape, _> = if rock {
1365                Rock.at(standing).into_set()
1366            } else {
1367                Bush.at(standing).into_set()
1368            };
1369            ctx.draw(flora.upright());
1370        }
1371    }
1372
1373    /// One stone box drawn on the ground at `at`, `size` across, sampling
1374    /// the part of the sheet `frame` covers.
1375    fn draw_stone(ctx: &mut FrameContext<'_, Keep>, at: Vec3, size: Vec3, frame: Frame) {
1376        ctx.draw(
1377            Stone
1378                .at(Transform::from_scale_rotation_translation(
1379                    size,
1380                    Quat::IDENTITY,
1381                    at + Vec3::Y * (size.y * 0.5),
1382                ))
1383                .frame(frame),
1384        );
1385    }
1386
1387    /// Two stone pillars drawn where `mouth` blocks the player, each a
1388    /// capital over its own course of masonry, and, on the one the camera
1389    /// looks into, the lintel across their tops and the dark filling
1390    /// the opening under it.
1391    fn draw_mouth(ctx: &mut FrameContext<'_, Keep>, mouth: Mouth) {
1392        for at in mouth.pillars() {
1393            Self::draw_stone(ctx, at, MOUTH_PILLAR_SIZE, Frame::default());
1394        }
1395        if !mouth.looked_into() {
1396            return;
1397        }
1398
1399        Self::draw_stone(
1400            ctx,
1401            mouth.at + Vec3::Y * MOUTH_PILLAR_SIZE.y,
1402            MOUTH_LINTEL_SIZE,
1403            masonry(MOUTH_LINTEL_TILES),
1404        );
1405        ctx.draw(
1406            Quad.at(Transform::from_scale_rotation_translation(
1407                Vec3::new(MOUTH_PILLAR_OFFSET * 2.0, MOUTH_DARK_HEIGHT, 1.0),
1408                Quat::IDENTITY,
1409                mouth.at + Vec3::Y * (MOUTH_DARK_HEIGHT * 0.5),
1410            ))
1411            .material(Material::color(Color::BLACK)),
1412        );
1413    }
1414
1415    fn draw_cave_floor(&self, ctx: &mut FrameContext<'_, Keep>) {
1416        let half = CAVE_HALF_WIDTH as i32;
1417        let near = CAVE_NEAR_Z as i32;
1418        let far = CAVE_FAR_Z as i32;
1419        for col in -half..=half {
1420            for row in far..=near {
1421                let variant = (col * 13 + row * 7).rem_euclid(CAVE_COLUMNS as i32) as u32;
1422                ctx.draw(
1423                    CaveFloor
1424                        .at(Vec3::new(
1425                            col as f32 * TILE_SIZE,
1426                            0.0,
1427                            row as f32 * TILE_SIZE,
1428                        ))
1429                        .frame(
1430                            Sheet::new(UVec2::new(CAVE_COLUMNS, CAVE_ROWS))
1431                                .cell_at(UVec2::new(variant, CAVE_FLOOR_ROW)),
1432                        ),
1433                );
1434            }
1435        }
1436    }
1437
1438    /// The wall drawn at `at` over the meters `standing`, in courses
1439    /// [`WALL_HEIGHT`] tall from the floor up, each cut to the part of it the
1440    /// span leaves; its faces are picked by `seed` and its stone faded to
1441    /// `fade`, which is `1.0` wherever it is solid.
1442    fn draw_wall(
1443        ctx: &mut FrameContext<'_, Keep>,
1444        at: Vec2,
1445        standing: Range<f32>,
1446        seed: i32,
1447        fade: f32,
1448    ) {
1449        for course in 0..WALL_COURSES {
1450            let base = course as f32 * WALL_HEIGHT;
1451            let low = (standing.start - base).max(0.0);
1452            let high = (standing.end - base).min(WALL_HEIGHT);
1453            if high <= low {
1454                continue;
1455            }
1456
1457            let variant = (seed + course).rem_euclid(CAVE_COLUMNS as i32) as u32;
1458            ctx.draw(
1459                CaveWall
1460                    .at(Transform::from_scale_rotation_translation(
1461                        Vec3::new(TILE_SIZE, high - low, TILE_SIZE),
1462                        Quat::IDENTITY,
1463                        Vec3::new(at.x, base + (low + high) * 0.5, at.y),
1464                    ))
1465                    .frame(cave_wall_face(variant, low..high))
1466                    .faded(fade),
1467            );
1468        }
1469    }
1470
1471    /// The room's two side walls and its back wall, full height, and the low
1472    /// wall closing its near end between the side walls and the mouth. The
1473    /// back wall stops short of the corners the side walls already fill, and
1474    /// the near one leaves the mouth's own tile open.
1475    fn draw_cave_walls(&self, ctx: &mut FrameContext<'_, Keep>) {
1476        let half = CAVE_HALF_WIDTH as i32 + 1;
1477        let near = CAVE_NEAR_Z as i32;
1478        let far = CAVE_FAR_Z as i32;
1479
1480        for row in far..=near {
1481            let z = row as f32 * TILE_SIZE;
1482            let west = Vec2::new(-half as f32 * TILE_SIZE, z);
1483            let east = Vec2::new(half as f32 * TILE_SIZE, z);
1484            Self::draw_wall(ctx, west, 0.0..WALL_TOP, row * 5, SOLID);
1485            Self::draw_wall(ctx, east, 0.0..WALL_TOP, row * 5 + 1, SOLID);
1486        }
1487        for col in (-half + 1)..half {
1488            let x = col as f32 * TILE_SIZE;
1489            let back = Vec2::new(x, far as f32 * TILE_SIZE);
1490            Self::draw_wall(ctx, back, 0.0..WALL_TOP, col * 5 + 2, SOLID);
1491            if col != 0 {
1492                let lip = Vec2::new(x, CAVE_LIP_Z);
1493                Self::draw_wall(ctx, lip, 0.0..CAVE_LIP_HEIGHT, col * 5 + 4, SOLID);
1494            }
1495        }
1496    }
1497
1498    /// The wall the door hangs in, run across the room between the side walls
1499    /// with one tile left open on the room's axis for the doorway and stone
1500    /// filling the column over the door. A player behind the wall is drawn
1501    /// through the stacks between them and the camera, at `seen_through`,
1502    /// faded by `ghost`; the rest of it stays solid, and keeps casting.
1503    fn draw_door_wall(ctx: &mut FrameContext<'_, Keep>, seen_through: Option<f32>, ghost: f32) {
1504        let stone = |x: f32| match seen_through {
1505            Some(at) if (x - at).abs() < GHOST_CORRIDOR_HALF => ghost_alpha(ghost),
1506            _ => SOLID,
1507        };
1508        let half = CAVE_HALF_WIDTH as i32;
1509
1510        for col in (-half..=half).filter(|&col| col != 0) {
1511            let x = col as f32 * TILE_SIZE;
1512            Self::draw_wall(
1513                ctx,
1514                Vec2::new(x, DOOR_Z),
1515                0.0..WALL_TOP,
1516                col * 5 + 3,
1517                stone(x),
1518            );
1519        }
1520        Self::draw_wall(
1521            ctx,
1522            Vec2::new(0.0, DOOR_Z),
1523            DOOR_HEIGHT..WALL_TOP,
1524            3,
1525            stone(0.0),
1526        );
1527    }
1528
1529    /// The two torches: an upright cutout post apiece, the flame's loop
1530    /// burning over its binding, and the light that flame casts.
1531    fn draw_torches(&self, ctx: &mut FrameContext<'_, Keep>) {
1532        let elapsed = self.simulated.as_secs_f32();
1533        let loop_cells = Sheet::new(UVec2::new(FLAME_CELLS, 1));
1534
1535        for (index, &(x, z)) in TORCH_POSITIONS.iter().enumerate() {
1536            let base = Vec3::new(x, 0.0, z);
1537            ctx.draw(
1538                Torch
1539                    .at(Transform::from_scale_rotation_translation(
1540                        Vec3::new(TORCH_SPRITE_WIDTH, TORCH_STAND_HEIGHT, 1.0),
1541                        Quat::IDENTITY,
1542                        base + Vec3::Y * (TORCH_STAND_HEIGHT * 0.5),
1543                    ))
1544                    .upright(),
1545            );
1546
1547            let phase = index as f32 * 2.1;
1548            let flicker = (elapsed * FLAME_FLICKER_SPEED + phase).sin();
1549            let flame_pos =
1550                base + Vec3::Y * (TORCH_STAND_HEIGHT + FLAME_LIFT + flicker * FLAME_BOB);
1551
1552            let light_pos = flame_pos + Vec3::new(0.0, TORCH_LIGHT_LIFT, TORCH_LIGHT_STANDOFF);
1553            ctx.light(Light::point(light_pos, TORCH_LIGHT_COLOR, TORCH_LIGHT_RANGE).shadow());
1554            // The pair burn an even share of the loop apart.
1555            let offset = index as u32 * FLAME_CELLS / TORCH_POSITIONS.len() as u32;
1556            ctx.draw(
1557                Flame
1558                    .at(Transform::from_scale_rotation_translation(
1559                        Vec3::splat(FLAME_SIZE),
1560                        Quat::IDENTITY,
1561                        flame_pos,
1562                    ))
1563                    .billboard()
1564                    .roll(flicker * FLAME_ROLL)
1565                    .frame(loop_cells.cell((elapsed * FLAME_RATE) as u32 + offset)),
1566            );
1567        }
1568    }
1569
1570    /// The door at its hinge — swung back against the wall once opened —
1571    /// drawn through alongside its wall, faded by `ghost`.
1572    fn draw_door(&self, ctx: &mut FrameContext<'_, Keep>, ghost: f32) {
1573        let fade = ghost_alpha(ghost);
1574        let swung = if self.door_opening {
1575            Quat::from_rotation_y(core::f32::consts::FRAC_PI_2)
1576        } else {
1577            Quat::IDENTITY
1578        };
1579
1580        ctx.draw(
1581            Door.at(Transform::from_rotation_translation(swung, DOOR_HINGE))
1582                .material(Material::shaded(DOOR_COLOR, DOOR_LITNESS))
1583                .faded(fade),
1584        );
1585    }
1586
1587    /// The posts and lintel framing the doorway, in a color the stone never
1588    /// is, standing clear of the wall so the opening reads as a door from
1589    /// across the chamber. Glowing of their own while the door is closed and
1590    /// within [`INTERACT_RADIUS`], the cue that it opens.
1591    fn draw_door_frame(&self, ctx: &mut FrameContext<'_, Keep>, ghost: f32) {
1592        let reachable =
1593            !self.door_opening && self.position.distance(INTERACT_POINT) < INTERACT_RADIUS;
1594        let material =
1595            Material::shaded(DOOR_FRAME_COLOR, DOOR_FRAME_LITNESS).emissive(if reachable {
1596                DOOR_FRAME_GLOW
1597            } else {
1598                Color::BLACK
1599            });
1600        let fade = ghost_alpha(ghost);
1601        let z = DOOR_WALL_NEAR_Z + DOOR_FRAME_STANDOFF;
1602        let jamb_height = DOOR_HEIGHT + DOOR_FRAME_THICKNESS;
1603
1604        for side in SIDES {
1605            ctx.draw(
1606                Cube.at(Transform::from_scale_rotation_translation(
1607                    Vec3::new(DOOR_FRAME_THICKNESS, jamb_height, DOOR_FRAME_THICKNESS),
1608                    Quat::IDENTITY,
1609                    Vec3::new(
1610                        side * (DOORWAY_HALF + DOOR_FRAME_THICKNESS * 0.5),
1611                        jamb_height * 0.5,
1612                        z,
1613                    ),
1614                ))
1615                .material(material)
1616                .faded(fade),
1617            );
1618        }
1619        ctx.draw(
1620            Cube.at(Transform::from_scale_rotation_translation(
1621                Vec3::new(
1622                    DOOR_WIDTH + DOOR_FRAME_THICKNESS * 2.0,
1623                    DOOR_FRAME_THICKNESS,
1624                    DOOR_FRAME_THICKNESS,
1625                ),
1626                Quat::IDENTITY,
1627                Vec3::new(0.0, DOOR_HEIGHT + DOOR_FRAME_THICKNESS * 0.5, z),
1628            ))
1629            .material(material)
1630            .faded(fade),
1631        );
1632    }
1633
1634    /// A world prompt over the door: what opens it while the player is
1635    /// within [`INTERACT_RADIUS`] and it is closed, and that it swings while
1636    /// it does; gone once it has swung [`DOOR_SWING_TICKS`]. Laid out and
1637    /// placed like `examples/animation.rs`'s own prompt.
1638    fn draw_door_prompt(&self, ctx: &mut FrameContext<'_, Keep>, camera: Camera) {
1639        let near = self.position.distance(INTERACT_POINT) < INTERACT_RADIUS;
1640        let swinging = self.door_opening && self.swing_ticks < DOOR_SWING_TICKS;
1641        let text = if swinging {
1642            "opening"
1643        } else if near && !self.door_opening {
1644            "e opens the door"
1645        } else {
1646            return;
1647        };
1648
1649        let galley = ctx.text_layout(text, egui::FontId::proportional(DOOR_PROMPT_SIZE));
1650        let point = INTERACT_POINT + Vec3::Y * (DOOR_HEIGHT + DOOR_PROMPT_LIFT);
1651        let window_size = ctx.window_size();
1652        let pixels_per_point = ctx.pixels_per_point();
1653        let Some(pixel) = camera.pixel_of(point, window_size) else {
1654            return;
1655        };
1656
1657        ctx.ui(|ui| {
1658            let painter = ui.painter();
1659            let at = logical(pixel, pixels_per_point);
1660            let ink = galley.mesh_bounds;
1661            let pos = egui::pos2(at.x - ink.center().x, at.y - ink.center().y);
1662            let backdrop = egui::Rect::from_center_size(
1663                at,
1664                ink.size() + egui::Vec2::splat(DOOR_PROMPT_PADDING * 2.0),
1665            );
1666            painter.rect_filled(
1667                backdrop,
1668                DOOR_PROMPT_PADDING,
1669                egui::Color32::from_black_alpha(DOOR_PROMPT_BACKDROP),
1670            );
1671            painter.galley(pos, galley, DOOR_PROMPT_COLOR);
1672        });
1673    }
1674
1675    /// The gem, spinning and bobbing over the chamber's floor, and the light
1676    /// it casts over it.
1677    fn draw_gem(&self, ctx: &mut FrameContext<'_, Keep>) {
1678        let t = self.simulated.as_secs_f32();
1679        let bob = (t * 2.0).sin() * GEM_BOB_HEIGHT;
1680        ctx.light(
1681            Light::point(
1682                GEM_POSITION + Vec3::Y * (bob + GEM_LIGHT_LIFT),
1683                GEM_LIGHT_COLOR,
1684                GEM_LIGHT_RANGE,
1685            )
1686            .shadow(),
1687        );
1688        ctx.draw(
1689            Gem.at(Transform::from_scale_rotation_translation(
1690                Vec3::ONE,
1691                Quat::from_rotation_y(t * GEM_SPIN_SPEED),
1692                GEM_POSITION + Vec3::Y * bob,
1693            ))
1694            .material(Material::shaded(GEM_COLOR, 0.7).emissive(GEM_COLOR.dimmed(1.6))),
1695        );
1696    }
1697
1698    /// The player: upright so it always faces the camera about `+Y`,
1699    /// windowed to its facing's row and the walk cycle's current frame.
1700    fn draw_walker(&self, ctx: &mut FrameContext<'_, Keep>, ground: Vec3) {
1701        let step = if self.walk_ticks > 0 {
1702            (self.walk_ticks / TICKS_PER_WALK_FRAME) % WALKER_COLUMNS
1703        } else {
1704            0
1705        };
1706        let cell = Sheet::new(UVec2::new(WALKER_COLUMNS, WALKER_ROWS))
1707            .cell_at(UVec2::new(step, self.facing as u32));
1708        let size = Vec2::new(WALKER_WIDTH, WALKER_HEIGHT);
1709
1710        ctx.draw(
1711            Walker
1712                .at(Transform::from_scale_rotation_translation(
1713                    size.extend(1.0),
1714                    Quat::IDENTITY,
1715                    ground + Vec3::Y * (WALKER_HEIGHT * 0.5),
1716                ))
1717                .upright()
1718                .frame(cell),
1719        );
1720    }
examples/sound-lab.rs (line 201)
188fn facing_marker() -> MeshData {
189    const TIP: Vec3 = Vec3::new(0.0, 0.0, -0.5);
190    const BACK: [Vec3; 4] = [
191        Vec3::new(-0.5, -0.5, 0.5),
192        Vec3::new(0.5, -0.5, 0.5),
193        Vec3::new(0.5, 0.5, 0.5),
194        Vec3::new(-0.5, 0.5, 0.5),
195    ];
196
197    let mut vertices = Vec::with_capacity(BACK.len() * 3);
198    for (corner, next) in BACK.iter().zip(BACK.iter().cycle().skip(1)) {
199        let normal = (next - corner).cross(TIP - corner).normalize();
200        vertices.extend([
201            Vertex::new(*corner, normal, Vec2::new(0.0, 1.0)),
202            Vertex::new(*next, normal, Vec2::new(1.0, 1.0)),
203            Vertex::new(TIP, normal, Vec2::new(0.5, 0.0)),
204        ]);
205    }
206    let indices = (0..vertices.len() as u32).collect();
207    MeshData::new(vertices, indices)
208}
209
210/// Every sound this game plays. [`Sound::Break`] and [`Sound::Pulse`] read the
211/// same source under two names, so sustaining one and playing the other
212/// once never share a voice; [`Sound::Theme`] and [`Sound::ThemeDecoded`] do
213/// the same for the streamed side against the decoded one, since a clip
214/// decodes one way or the other for good, once built.
215#[derive(Catalog, Clone, Copy, PartialEq, Eq, Hash)]
216enum Sound {
217    Bounce,
218    Break,
219    Serve,
220    GameOver,
221    Lost,
222    Win,
223    Click,
224    Theme,
225    ThemeDecoded,
226    MenuTheme,
227    Pulse,
228}
229
230impl Sound {
231    /// The alternatives a one-shot play offers.
232    const ONE_SHOTS: [Sound; 7] = [
233        Sound::Bounce,
234        Sound::Break,
235        Sound::Serve,
236        Sound::GameOver,
237        Sound::Lost,
238        Sound::Win,
239        Sound::Click,
240    ];
241
242    /// The alternatives one source's sustain offers.
243    const SOURCE_CHOICES: [Sound; 9] = [
244        Sound::Bounce,
245        Sound::Break,
246        Sound::Serve,
247        Sound::GameOver,
248        Sound::Lost,
249        Sound::Win,
250        Sound::Click,
251        Sound::Theme,
252        Sound::ThemeDecoded,
253    ];
254
255    fn label(self) -> &'static str {
256        match self {
257            Sound::Bounce => "bounce",
258            Sound::Break => "break",
259            Sound::Serve => "serve",
260            Sound::GameOver => "game over",
261            Sound::Lost => "lost",
262            Sound::Win => "win",
263            Sound::Click => "click",
264            Sound::Theme => "theme (streamed)",
265            Sound::ThemeDecoded => "theme (decoded)",
266            Sound::MenuTheme => "menu theme",
267            Sound::Pulse => "pulse",
268        }
269    }
270}
271
272impl Sounds for Sound {
273    fn build(&self, assets: &Assets) -> SoundData {
274        match self {
275            Sound::Bounce => assets.sound("bounce"),
276            Sound::Break => assets.sound("break"),
277            Sound::Serve => assets.sound("serve"),
278            Sound::GameOver => assets.sound("gameover"),
279            Sound::Lost => assets.sound("lost"),
280            Sound::Win => assets.sound("win"),
281            Sound::Click => assets.sound("click"),
282            Sound::Theme => assets.sound("music").streamed(),
283            Sound::ThemeDecoded => assets.sound("music"),
284            Sound::MenuTheme => assets.sound("menu_music").streamed(),
285            Sound::Pulse => assets.sound("break"),
286        }
287    }
288}
289
290/// The one button this game reads: it holds a source down and moves it.
291#[derive(InputButtonAction, Clone, Copy, PartialEq)]
292enum Button {
293    Select,
294}
295
296impl InputButtonAction for Button {
297    fn bindings(&self) -> Vec<ButtonBinding> {
298        match self {
299            Button::Select => vec![MouseButton::Left.into()],
300        }
301    }
302}
303
304/// The listener's walk, in the ground plane.
305#[derive(InputAxis2Action, Clone, Copy, PartialEq)]
306enum Move {
307    Walk,
308}
309
310impl InputAxis2Action for Move {
311    fn bindings(&self) -> Vec<Axis2Binding> {
312        match self {
313            Move::Walk => vec![
314                Axis2Binding::from(ButtonAxis2 {
315                    left: Key::A,
316                    right: Key::D,
317                    down: Key::S,
318                    up: Key::W,
319                }),
320                Axis2Binding::stick(Stick::Left),
321            ],
322        }
323    }
324}
325
326struct Controls;
327
328impl InputActions for Controls {
329    type Button = Button;
330    type Axis = NoInputAxes;
331    type Axis2 = Move;
332}
333
334/// One source a drag moves: a cube on the ground, playing a sustained clip
335/// with its own gain, reference, range, and pitch.
336struct Source {
337    position: Vec3,
338    sound: Sound,
339    gain: f32,
340    reference: f32,
341    range: f32,
342    pitch: f32,
343    /// Whether this source sustains at all; off keeps startup silent.
344    enabled: bool,
345}
346
347impl Source {
348    fn new(x: f32, z: f32, sound: Sound, range: f32, enabled: bool) -> Self {
349        Self {
350            position: Vec3::new(x, SOURCE_HEIGHT, z),
351            sound,
352            gain: 0.5,
353            reference: SOURCE_REFERENCE,
354            range,
355            pitch: 1.0,
356            enabled,
357        }
358    }
359
360    /// This source's sustained cue, with the loop point that seeks far
361    /// where its choice needs one.
362    fn cue(&self) -> SoundCue<Sound> {
363        let cue = self
364            .sound
365            .at(self.position)
366            .gain(self.gain)
367            .reference(self.reference)
368            .range(self.range)
369            .pitch(self.pitch);
370        match self.sound {
371            Sound::Theme | Sound::ThemeDecoded => cue.loop_from(THEME_LOOP_FROM),
372            _ => cue,
373        }
374    }
375}
376
377struct SoundCheck {
378    master_volume: f32,
379
380    picked: Sound,
381    one_shot_gain: f32,
382    one_shot_pitch: f32,
383    one_shot_fade: f32,
384    trim_start: f32,
385    trim_end: f32,
386    one_shot_loop_from: f32,
387
388    theme_on: bool,
389    menu_on: bool,
390    pulse_on: bool,
391    cue_fade: f32,
392
393    /// Sustains [`Sound::Click`] at [`MERGE_POS_A`] and [`MERGE_POS_B`]
394    /// both at the default instance: shows the merge each source's own
395    /// instance above keeps clear of.
396    merge_demo: bool,
397
398    /// Declares [`RING_COUNT`] sustains at once, more than the engine
399    /// plays, so that the cap is heard as it allocates by level.
400    ring_demo: bool,
401
402    player: Vec2,
403    player_prev: Vec2,
404    sources: [Source; 3],
405    dragging: Option<usize>,
406
407    /// Every catalog value's length, read once at startup.
408    durations: HashMap<Sound, Duration>,
409}
410
411impl SoundCheck {
412    fn init(ctx: &mut InitContext<'_, SoundCheck>) -> Result<Self, Error> {
413        let durations = ctx.durations();
414
415        let picked = Sound::Bounce;
416        let trim_end = durations.get(&picked).copied().unwrap_or_default();
417
418        Ok(Self {
419            master_volume: 1.0,
420
421            picked,
422            one_shot_gain: 1.0,
423            one_shot_pitch: 1.0,
424            one_shot_fade: SoundCue::<Sound>::DEFAULT_FADE.as_secs_f32(),
425            trim_start: 0.0,
426            trim_end: trim_end.as_secs_f32(),
427            one_shot_loop_from: 0.0,
428
429            theme_on: false,
430            menu_on: false,
431            pulse_on: false,
432            cue_fade: 1.0,
433
434            merge_demo: false,
435            ring_demo: false,
436
437            player: Vec2::ZERO,
438            player_prev: Vec2::ZERO,
439            sources: [
440                Source::new(-2.5, -2.0, Sound::Bounce, 4.0, false),
441                Source::new(2.5, -2.0, Sound::Serve, 4.0, false),
442                Source::new(0.0, 2.8, Sound::Theme, 7.0, true),
443            ],
444            dragging: None,
445
446            durations,
447        })
448    }
449
450    fn camera(player: Vec2) -> Camera {
451        let ground = Vec3::new(player.x, 0.0, player.y);
452        Camera::new(
453            View::look_at(
454                ground + Vec3::new(0.0, CHASE_UP, CHASE_BACK),
455                ground + Vec3::Y * 0.5,
456            ),
457            Projection::perspective(55.0),
458        )
459    }
460
461    fn handle_walk(&mut self, ctx: &mut TickContext<'_, SoundCheck>) {
462        self.player_prev = self.player;
463        if ctx.ui_wants_keyboard() {
464            return;
465        }
466        let walk = ctx.axis2(Move::Walk);
467        let world = Vec2::new(walk.x, -walk.y);
468        self.player = (self.player + world * WALK_SPEED * ctx.dt().as_secs_f32())
469            .clamp(Vec2::splat(-PLAY_BOUND), Vec2::splat(PLAY_BOUND));
470    }
471
472    /// Takes hold of the source a click's ray intersects, moves it across
473    /// the floor while the button stays down, and frees it on release.
474    fn handle_drag(&mut self, ctx: &mut TickContext<'_, SoundCheck>) {
475        // Read before the check below for the UI's own claim on the
476        // pointer, so a release over it still frees a source a drag moved
477        // there.
478        if ctx.released(Button::Select) {
479            self.dragging = None;
480        }
481        if ctx.ui_wants_pointer() {
482            return;
483        }
484        let ray = ctx
485            .last_camera()
486            .ray_through(ctx.pointer(), ctx.window_size());
487
488        if ctx.pressed(Button::Select) {
489            self.dragging = self.sources.iter().position(|source| {
490                ray.hit_sphere(source.position, SOURCE_PICK_RADIUS)
491                    .is_some()
492            });
493        }
494
495        let Some(index) = self.dragging else {
496            return;
497        };
498        let Some(distance) = ray.hit_plane(ray::Plane {
499            point: Vec3::ZERO,
500            normal: Vec3::Y,
501        }) else {
502            return;
503        };
504        let hit = ray.at(distance);
505        let dropped =
506            Vec2::new(hit.x, hit.z).clamp(Vec2::splat(-PLAY_BOUND), Vec2::splat(PLAY_BOUND));
507        self.sources[index].position = Vec3::new(dropped.x, SOURCE_HEIGHT, dropped.y);
508    }
examples/material-playground.rs (line 370)
360fn banner_mesh() -> MeshData {
361    let mut vertices = Vec::with_capacity(((BANNER_COLUMNS + 1) * 4) as usize);
362    for normal in [Vec3::Z, Vec3::NEG_Z] {
363        for column in 0..=BANNER_COLUMNS {
364            let u = column as f32 / BANNER_COLUMNS as f32;
365            let x = u * BANNER_WIDTH;
366            for v in [0.0, 1.0] {
367                vertices.push(Vertex::new(
368                    Vec3::new(x, -v * BANNER_HEIGHT, 0.0),
369                    normal,
370                    Vec2::new(u, v),
371                ));
372            }
373        }
374    }
375
376    let side = BANNER_COLUMNS + 1;
377    let mut indices = Vec::with_capacity((BANNER_COLUMNS * 12) as usize);
378    for column in 0..BANNER_COLUMNS {
379        let top_left = column * 2;
380        let bottom_left = top_left + 1;
381        let top_right = top_left + 2;
382        let bottom_right = top_left + 3;
383        indices.extend([
384            bottom_left,
385            bottom_right,
386            top_right,
387            bottom_left,
388            top_right,
389            top_left,
390        ]);
391
392        let back = side * 2;
393        indices.extend([
394            back + top_right,
395            back + bottom_right,
396            back + bottom_left,
397            back + top_left,
398            back + top_right,
399            back + bottom_left,
400        ]);
401    }
402
403    MeshData::new(vertices, indices)
404}
examples/isometric-board.rs (line 746)
724fn build_rock(seed: u32) -> MeshData {
725    let corners: [Vec3; 8] = core::array::from_fn(|index| {
726        let sign = Vec3::new(
727            if index & 1 == 0 { -0.5 } else { 0.5 },
728            if index & 2 == 0 { -0.5 } else { 0.5 },
729            if index & 4 == 0 { -0.5 } else { 0.5 },
730        );
731        sign + corner_offset(seed, index as u32)
732    });
733    let corner_at = |sign: Vec3| corners[corner_index(sign)];
734
735    let mut vertices = Vec::with_capacity(ROCK_FACES.len() * 4);
736    let mut indices = Vec::with_capacity(ROCK_FACES.len() * 6);
737    for (face, &(normal, right, up)) in ROCK_FACES.iter().enumerate() {
738        let quad = [
739            corner_at(normal - right - up),
740            corner_at(normal + right - up),
741            corner_at(normal + right + up),
742            corner_at(normal - right + up),
743        ];
744        let normal = (quad[1] - quad[0]).cross(quad[3] - quad[0]).normalize();
745        let uvs = [
746            Vec2::new(0.0, 1.0),
747            Vec2::new(1.0, 1.0),
748            Vec2::new(1.0, 0.0),
749            Vec2::new(0.0, 0.0),
750        ];
751        vertices.extend(
752            quad.into_iter()
753                .zip(uvs)
754                .map(|(corner, uv)| Vertex::new(corner, normal, uv)),
755        );
756        let base = face as u32 * 4;
757        indices.extend(ROCK_TRIANGLES.map(|index| base + index));
758    }
759    MeshData::new(vertices, indices)
760}
Source

pub const fn splat(v: f32) -> Vec2

Creates a vector with all elements set to v.

Examples found in repository?
examples/sound-lab.rs (line 469)
461    fn handle_walk(&mut self, ctx: &mut TickContext<'_, SoundCheck>) {
462        self.player_prev = self.player;
463        if ctx.ui_wants_keyboard() {
464            return;
465        }
466        let walk = ctx.axis2(Move::Walk);
467        let world = Vec2::new(walk.x, -walk.y);
468        self.player = (self.player + world * WALK_SPEED * ctx.dt().as_secs_f32())
469            .clamp(Vec2::splat(-PLAY_BOUND), Vec2::splat(PLAY_BOUND));
470    }
471
472    /// Takes hold of the source a click's ray intersects, moves it across
473    /// the floor while the button stays down, and frees it on release.
474    fn handle_drag(&mut self, ctx: &mut TickContext<'_, SoundCheck>) {
475        // Read before the check below for the UI's own claim on the
476        // pointer, so a release over it still frees a source a drag moved
477        // there.
478        if ctx.released(Button::Select) {
479            self.dragging = None;
480        }
481        if ctx.ui_wants_pointer() {
482            return;
483        }
484        let ray = ctx
485            .last_camera()
486            .ray_through(ctx.pointer(), ctx.window_size());
487
488        if ctx.pressed(Button::Select) {
489            self.dragging = self.sources.iter().position(|source| {
490                ray.hit_sphere(source.position, SOURCE_PICK_RADIUS)
491                    .is_some()
492            });
493        }
494
495        let Some(index) = self.dragging else {
496            return;
497        };
498        let Some(distance) = ray.hit_plane(ray::Plane {
499            point: Vec3::ZERO,
500            normal: Vec3::Y,
501        }) else {
502            return;
503        };
504        let hit = ray.at(distance);
505        let dropped =
506            Vec2::new(hit.x, hit.z).clamp(Vec2::splat(-PLAY_BOUND), Vec2::splat(PLAY_BOUND));
507        self.sources[index].position = Vec3::new(dropped.x, SOURCE_HEIGHT, dropped.y);
508    }
More examples
Hide additional examples
examples/sprite-adventure.rs (line 482)
480    fn push_out(self, point: Vec2, radius: f32) -> Vec2 {
481        let delta = point - self.center;
482        let escape = self.half + Vec2::splat(radius) - delta.abs();
483
484        if escape.min_element() <= 0.0 {
485            point
486        } else if escape.x < escape.y {
487            let x = self.center.x + delta.x.signum() * (self.half.x + radius);
488            Vec2::new(x, point.y)
489        } else {
490            let z = self.center.y + delta.y.signum() * (self.half.y + radius);
491            Vec2::new(point.x, z)
492        }
493    }
494}
495
496/// A cave mouth's opening: where it is, and which way along `Z` the room
497/// it leads out of lies.
498#[derive(Clone, Copy)]
499struct Mouth {
500    at: Vec3,
501    room_side: f32,
502}
503
504impl Mouth {
505    /// True where `position` lies between the pillars and past the plane
506    /// in front of the opening — where the only two outcomes are stepping
507    /// through and being held.
508    fn holds(&self, position: Vec3) -> bool {
509        let plane = self.at.z + self.room_side * MOUTH_CROSSING_INSET;
510
511        (position.x - self.at.x).abs() < MOUTH_OPENING_HALF
512            && (plane - position.z) * self.room_side > 0.0
513    }
514
515    /// Position of each of the two pillars flanking the opening.
516    fn pillars(&self) -> impl Iterator<Item = Vec3> + Clone {
517        let at = self.at;
518
519        SIDES
520            .into_iter()
521            .map(move |side| at + Vec3::X * (side * MOUTH_PILLAR_OFFSET))
522    }
523
524    /// True when the camera looks into this mouth: it always lies on `+Z`
525    /// of the player, so the mouth whose room lies that way is the one seen
526    /// from the room's side, and the one to fill with a lintel and the dark
527    /// under it. The other is looked through from behind, and leaves its
528    /// opening clear for the room to show through.
529    fn looked_into(&self) -> bool {
530        self.room_side > 0.0
531    }
532}
533
534// ---------------------------------------------------------------------
535// The water style
536// ---------------------------------------------------------------------
537
538/// The pond's whole look, over the one value it reads: how far its ripple
539/// has traveled.
540#[derive(Default, ShaderValues)]
541struct Water {
542    time: f32,
543}
544
545impl SurfaceStyle for Water {
546    const PASS: DrawPass = DrawPass::Translucent;
547    const SURFACE: Option<&'static str> = Some(include_str!("sprite_adventure_water.wgsl"));
548}
549
550surface_styles! { enum Looks { Water } }
551
552// ---------------------------------------------------------------------
553// Meshes
554// ---------------------------------------------------------------------
555
556/// The player's current area; never both drawn in one frame.
557#[derive(Clone, Copy, PartialEq, Eq)]
558enum Area {
559    Overworld,
560    Cave,
561}
562
563/// The overworld's ground tile, its texture the only thing that separates a
564/// draw of it from another.
565#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
566struct Ground;
567
568impl Mesh for Ground {
569    fn build(&self, assets: &Assets) -> MeshData {
570        Plane
571            .build(assets)
572            .with_texture(assets.texture(GROUND_SHEET).pixelated())
573    }
574}
575
576/// The shoreline sprite laid over the pond's styled water, cutout so the
577/// water shows through its cleared middle.
578#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
579struct Shore;
580
581impl Mesh for Shore {
582    fn build(&self, assets: &Assets) -> MeshData {
583        Plane
584            .build(assets)
585            .with_texture(assets.texture(POND_SHEET).pixelated())
586            .with_material(Material::lit(Color::WHITE).cutout())
587    }
588}
589
590/// A crate prop, its texture drawn over a cube.
591#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
592struct Crate;
593
594impl Mesh for Crate {
595    fn build(&self, assets: &Assets) -> MeshData {
596        Cube.build(assets)
597            .with_texture(assets.texture(CRATE_TEXTURE).pixelated())
598    }
599}
600
601/// The well's rim.
602#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
603struct Well;
604
605impl Mesh for Well {
606    fn build(&self, assets: &Assets) -> MeshData {
607        Cube.build(assets)
608            .with_texture(assets.texture(WELL_SHEET).pixelated())
609    }
610}
611
612/// The well's mouth, laid flat over the rim's top face.
613#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
614struct WellMouth;
615
616impl Mesh for WellMouth {
617    fn build(&self, assets: &Assets) -> MeshData {
618        Plane
619            .build(assets)
620            .with_texture(assets.texture(WELL_SHEET).pixelated())
621    }
622}
623
624/// A stone box: the mouth's pillars and lintel.
625#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
626struct Stone;
627
628impl Mesh for Stone {
629    fn build(&self, assets: &Assets) -> MeshData {
630        Cube.build(assets)
631            .with_texture(assets.texture(STONE_SHEET).pixelated())
632    }
633}
634
635/// A bush sprite, cutout with its own relief.
636#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
637struct Bush;
638
639impl Mesh for Bush {
640    fn build(&self, assets: &Assets) -> MeshData {
641        Quad.build(assets)
642            .with_texture(assets.texture(BUSH_SPRITE).pixelated())
643            .with_relief(assets.relief(BUSH_RELIEF))
644            .with_material(Material::lit(Color::WHITE).cutout())
645    }
646}
647
648/// A rock sprite, cutout with its own relief.
649#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
650struct Rock;
651
652impl Mesh for Rock {
653    fn build(&self, assets: &Assets) -> MeshData {
654        Quad.build(assets)
655            .with_texture(assets.texture(ROCK_SPRITE).pixelated())
656            .with_relief(assets.relief(ROCK_RELIEF))
657            .with_material(Material::lit(Color::WHITE).cutout())
658    }
659}
660
661/// A torch's post sprite, cutout with its own relief.
662#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
663struct Torch;
664
665impl Mesh for Torch {
666    fn build(&self, assets: &Assets) -> MeshData {
667        Quad.build(assets)
668            .with_texture(assets.texture(TORCH_SPRITE).pixelated())
669            .with_relief(assets.relief(TORCH_RELIEF))
670            .with_material(Material::lit(Color::WHITE).cutout())
671    }
672}
673
674/// A torch's flame sprite, added over the dark rather than lit.
675#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
676struct Flame;
677
678impl Mesh for Flame {
679    fn build(&self, assets: &Assets) -> MeshData {
680        Quad.build(assets)
681            .with_texture(assets.texture(FLAME_SHEET).pixelated())
682            .with_material(Material::color(FLAME_TINT).additive())
683    }
684}
685
686/// The player's sprite, cutout with its own relief, its sheet shared
687/// with `examples/isometric-board.rs`.
688#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
689struct Walker;
690
691impl Mesh for Walker {
692    fn build(&self, assets: &Assets) -> MeshData {
693        Quad.build(assets)
694            .with_texture(assets.texture(WALKER_SHEET).pixelated())
695            .with_relief(assets.relief(WALKER_RELIEF))
696            .with_material(Material::lit(Color::WHITE).cutout())
697    }
698}
699
700/// The cave floor tile.
701#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
702struct CaveFloor;
703
704impl Mesh for CaveFloor {
705    fn build(&self, assets: &Assets) -> MeshData {
706        Plane
707            .build(assets)
708            .with_texture(assets.texture(CAVE_SHEET).pixelated())
709    }
710}
711
712/// The cave wall face.
713#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
714struct CaveWall;
715
716impl Mesh for CaveWall {
717    fn build(&self, assets: &Assets) -> MeshData {
718        Cube.build(assets)
719            .with_texture(assets.texture(CAVE_SHEET).pixelated())
720    }
721}
722
723/// The loaded door, drawn as its source authored it.
724#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
725struct Door;
726
727impl Mesh for Door {
728    fn build(&self, assets: &Assets) -> MeshData {
729        assets.mesh(DOOR_MESH)
730    }
731}
732
733/// The loaded gem, repainted whole per draw so its glow color shifts.
734#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
735struct Gem;
736
737impl Mesh for Gem {
738    fn build(&self, assets: &Assets) -> MeshData {
739        assets.mesh(GEM_MESH)
740    }
741}
742
743// Everything this game can draw: the meshes above, plus the styled water,
744// the dark filling a looked-into mouth's opening, and the door's own frame,
745// which draw the bare engine primitives Plane, Quad and Cube.
746meshes! {
747    enum Shape {
748        Ground, Shore, Crate, Well, WellMouth, Stone, Bush, Rock, Torch,
749        Flame, Walker, CaveFloor, CaveWall, Door, Gem, Plane, Quad, Cube,
750    }
751}
752
753/// The interact click and the gem's chime, shared with the other examples.
754#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
755enum Sound {
756    Interact,
757    Gem,
758}
759
760impl Sounds for Sound {
761    fn build(&self, assets: &Assets) -> SoundData {
762        match self {
763            Sound::Interact => assets.sound("click"),
764            Sound::Gem => assets.sound("win"),
765        }
766    }
767}
768
769// ---------------------------------------------------------------------
770// Input
771// ---------------------------------------------------------------------
772
773/// Player movement: `WASD`, arrows, or a stick — the strongest reading is
774/// kept.
775#[derive(InputAxis2Action, Clone, Copy, PartialEq)]
776enum Move {
777    Walk,
778}
779
780impl InputAxis2Action for Move {
781    fn bindings(&self) -> Vec<Axis2Binding> {
782        match self {
783            Move::Walk => vec![
784                Axis2Binding::from(ButtonAxis2 {
785                    left: Key::A,
786                    right: Key::D,
787                    down: Key::S,
788                    up: Key::W,
789                }),
790                Axis2Binding::from(ButtonAxis2 {
791                    left: Key::Left,
792                    right: Key::Right,
793                    down: Key::Down,
794                    up: Key::Up,
795                }),
796                Axis2Binding::stick(Stick::Left),
797            ],
798        }
799    }
800}
801
802/// The two verbs this game reads as an edge: interacting with the door, and
803/// a reset of the world to every saved key's fallback.
804#[derive(InputButtonAction, Clone, Copy, PartialEq)]
805enum Button {
806    Interact,
807    Reset,
808}
809
810impl InputButtonAction for Button {
811    fn bindings(&self) -> Vec<ButtonBinding> {
812        match self {
813            Button::Interact => vec![Key::E.into(), Pad::West.into()],
814            Button::Reset => vec![Key::R.into()],
815        }
816    }
817}
818
819struct Controls;
820
821impl InputActions for Controls {
822    type Button = Button;
823    type Axis = NoInputAxes;
824    type Axis2 = Move;
825}
826
827// ---------------------------------------------------------------------
828// Save data
829// ---------------------------------------------------------------------
830
831/// The player's last position, read at startup and saved on area
832/// transition and gem pickup.
833#[derive(Saves, Clone, Copy)]
834enum Position {
835    X,
836    Z,
837}
838
839impl SaveKey for Position {
840    type Value = f64;
841
842    fn fallback(&self) -> f64 {
843        match self {
844            Position::X => PLAYER_SPAWN.x as f64,
845            Position::Z => PLAYER_SPAWN.z as f64,
846        }
847    }
848}
849
850/// The area the player is in, and whether the gem is taken.
851#[derive(Saves, Clone, Copy)]
852enum Flag {
853    InCave,
854    GemTaken,
855}
856
857impl SaveKey for Flag {
858    type Value = bool;
859
860    fn fallback(&self) -> bool {
861        false
862    }
863}
864
865// ---------------------------------------------------------------------
866// The player's facing
867// ---------------------------------------------------------------------
868
869/// The player's last facing: also its row in the sheet, top to bottom.
870#[derive(Clone, Copy, PartialEq)]
871enum Facing {
872    Toward = 0,
873    Right = 1,
874    Away = 2,
875    Left = 3,
876}
877
878impl Facing {
879    /// The facing `heading` points in, favoring its larger axis; `None` at
880    /// rest, so the caller can keep the last facing.
881    fn from_heading(heading: Vec2) -> Option<Self> {
882        if heading == Vec2::ZERO {
883            return None;
884        }
885        Some(if heading.x.abs() > heading.y.abs() {
886            if heading.x > 0.0 {
887                Self::Right
888            } else {
889                Self::Left
890            }
891        } else if heading.y > 0.0 {
892            Self::Away
893        } else {
894            Self::Toward
895        })
896    }
897}
898
899// ---------------------------------------------------------------------
900// The game
901// ---------------------------------------------------------------------
902
903/// The ground tile at `col, row`: the path's dirt along [`PATH_COLUMN`],
904/// the verges that edge it, and a hashed grass variant everywhere else.
905fn ground_cell(col: i32, row: i32) -> Frame {
906    let (column, sheet_row) = match col - PATH_COLUMN {
907        0 => (PATH_DIRT + row.rem_euclid(2) as u32, PATH_ROW),
908        -1 => (PATH_WEST_VERGE, PATH_ROW),
909        1 => (PATH_EAST_VERGE, PATH_ROW),
910        _ => (
911            (col * 31 + row * 17).rem_euclid(GROUND_COLUMNS as i32) as u32,
912            GRASS_ROW,
913        ),
914    };
915
916    Sheet::new(UVec2::new(GROUND_COLUMNS, GROUND_ROWS)).cell_at(UVec2::new(column, sheet_row))
917}
918
919/// The stone sheet's plain masonry, laid `tiles` times across: the sampler
920/// wraps, so a window wider than the sheet repeats the course.
921fn masonry(tiles: f32) -> Frame {
922    let course = 1.0 / STONE_ROWS as f32;
923
924    Frame::rect(Vec2::new(0.0, 1.0 - course), Vec2::new(tiles, 1.0))
925}
926
927/// The wall or door's alpha `fraction` of the way from [`SOLID`] to
928/// [`GHOST_ALPHA`].
929fn ghost_alpha(fraction: f32) -> f32 {
930    SOLID + (GHOST_ALPHA - SOLID) * fraction
931}
932
933/// The wall face in column `variant`, windowed to the meters `standing` of
934/// one course, measured up from that course's own base: every row of the
935/// cave sheet below the floor's covers [`WALL_HEIGHT`], so a course keeps
936/// the floor's texels to the meter however it is cut.
937fn cave_wall_face(variant: u32, standing: Range<f32>) -> Frame {
938    let cell = Vec2::new(1.0 / CAVE_COLUMNS as f32, 1.0 / CAVE_ROWS as f32);
939    let left = (variant % CAVE_COLUMNS) as f32 * cell.x;
940    let face = (CAVE_FLOOR_ROW + 1) as f32 * cell.y;
941    let up_from_base = |height: f32| 1.0 - (1.0 - face) * (height / WALL_HEIGHT);
942
943    Frame::rect(
944        Vec2::new(left, up_from_base(standing.end)),
945        Vec2::new(left + cell.x, up_from_base(standing.start)),
946    )
947}
948
949/// The logical point egui paints the physical pixel `pixel` at.
950fn logical(pixel: Vec2, pixels_per_point: f32) -> egui::Pos2 {
951    let point = pixel / pixels_per_point;
952    egui::pos2(point.x, point.y)
953}
954
955fn main() {
956    run(
957        Config::new("Mirage: sprite adventure")
958            .with_size(1280, 720)
959            .with_assets([
960                MODEL,
961                WALKER_SOURCE,
962                WALKER_RELIEF_SOURCE,
963                GROUND_SOURCE,
964                BUSH_SOURCE,
965                BUSH_RELIEF_SOURCE,
966                ROCK_SOURCE,
967                ROCK_RELIEF_SOURCE,
968                TORCH_RELIEF_SOURCE,
969                CRATE_SOURCE,
970                WELL_SOURCE,
971                STONE_SOURCE,
972                CAVE_SOURCE,
973                POND_SOURCE,
974                TORCH_SOURCE,
975                FLAME_SOURCE,
976                INTERACT_SOUND,
977                GEM_SOUND,
978            ]),
979        Keep::init,
980    );
981}
982
983struct Keep {
984    area: Area,
985    position: Vec3,
986    previous: Vec3,
987    facing: Facing,
988    walk_ticks: u32,
989    simulated: Duration,
990    door_opening: bool,
991    /// Ticks the door has been opening for, at a cap of
992    /// [`DOOR_SWING_TICKS`]: how long its world prompt reads "opening" once
993    /// it starts.
994    swing_ticks: u32,
995    gem_taken: bool,
996    /// How far the door wall's fade from [`SOLID`] to [`GHOST_ALPHA`] has
997    /// run as of the last tick: `0.0` to `1.0`.
998    ghost: f32,
999    /// Set by the panel's reset button, since its click lands in a frame
1000    /// rather than a tick; read and cleared on the next tick.
1001    reset_requested: bool,
1002}
1003
1004impl Keep {
1005    /// Prepares every startup-cataloged mesh and resumes wherever the last
1006    /// run left the player.
1007    fn init(ctx: &mut InitContext<'_, Keep>) -> Result<Self, Error> {
1008        let startup = ctx.startup();
1009        let gem_taken = startup.saved(Flag::GemTaken);
1010        let area = if startup.saved(Flag::InCave) {
1011            Area::Cave
1012        } else {
1013            Area::Overworld
1014        };
1015        let position = Vec3::new(
1016            startup.saved(Position::X) as f32,
1017            0.0,
1018            startup.saved(Position::Z) as f32,
1019        );
1020
1021        Ok(Self {
1022            area,
1023            position,
1024            previous: position,
1025            facing: Facing::Toward,
1026            walk_ticks: 0,
1027            simulated: Duration::ZERO,
1028            door_opening: gem_taken,
1029            swing_ticks: if gem_taken { DOOR_SWING_TICKS } else { 0 },
1030            gem_taken,
1031            ghost: 0.0,
1032            reset_requested: false,
1033        })
1034    }
1035
1036    fn camera(position: Vec3, offset: Vec3) -> Camera {
1037        Camera::new(
1038            View::look_at(position + offset, position),
1039            Projection::perspective(CAMERA_FOV),
1040        )
1041    }
1042
1043    /// Obstacles from the overworld's props: the crates, turned as they are
1044    /// drawn, the well's rim, the open water the shoreline rings, the
1045    /// mouth's pillars, and each flora's base.
1046    fn overworld_obstacles() -> impl Iterator<Item = Obstacle> + Clone {
1047        CRATE_POSITIONS
1048            .into_iter()
1049            .map(|(x, z, turn)| {
1050                Obstacle::footprint(Vec2::new(x, z), Vec2::splat(CRATE_SIZE * turned_span(turn)))
1051            })
1052            .chain([
1053                Obstacle::footprint(WELL_POSITION.xz(), WELL_SIZE.xz()),
1054                Obstacle::footprint(POND_CENTER.xz(), Vec2::splat(POND_WATER_HALF * 2.0)),
1055            ])
1056            .chain(
1057                ENTRANCE
1058                    .pillars()
1059                    .map(|at| Obstacle::footprint(at.xz(), MOUTH_PILLAR_SIZE.xz())),
1060            )
1061            .chain(FLORA.into_iter().map(|(x, z, rock)| {
1062                let base = if rock { ROCK_FOOTPRINT } else { BUSH_FOOTPRINT };
1063                Obstacle::footprint(Vec2::new(x, z), Vec2::splat(base))
1064            }))
1065    }
1066
1067    /// Obstacles from the cave: the torch posts, its own mouth's pillars,
1068    /// the runs of wall either side of the doorway and of the mouth, and the
1069    /// `door` leaf.
1070    fn cave_obstacles(door: Obstacle) -> impl Iterator<Item = Obstacle> + Clone {
1071        TORCH_POSITIONS
1072            .into_iter()
1073            .map(|(x, z)| Obstacle::footprint(Vec2::new(x, z), Vec2::splat(TORCH_STAND_WIDTH)))
1074            .chain(
1075                EXIT.pillars()
1076                    .map(|at| Obstacle::footprint(at.xz(), MOUTH_PILLAR_SIZE.xz())),
1077            )
1078            .chain(SIDES.into_iter().flat_map(|side| {
1079                [
1080                    Self::wall_run(side, DOOR_Z),
1081                    Self::wall_run(side, CAVE_LIP_Z),
1082                ]
1083            }))
1084            .chain([door])
1085    }
Source

pub fn map<F>(self, f: F) -> Vec2
where F: FnMut(f32) -> f32,

Returns a vector containing each element of self modified by a mapping function f.

Source

pub fn select(mask: BVec2, if_true: Vec2, if_false: Vec2) -> Vec2

Creates a vector from the elements in if_true and if_false, selecting which to use for each element of self.

A true element in the mask uses the corresponding element from if_true, and false uses the element from if_false.

Source

pub const fn from_array(a: [f32; 2]) -> Vec2

Creates a new vector from an array.

Source

pub const fn to_array(&self) -> [f32; 2]

Converts self to [x, y]

Source

pub const fn from_slice(slice: &[f32]) -> Vec2

Creates a vector from the first 2 values in slice.

§Panics

Panics if slice is less than 2 elements long.

Source

pub fn write_to_slice(self, slice: &mut [f32])

Writes the elements of self to the first 2 elements in slice.

§Panics

Panics if slice is less than 2 elements long.

Source

pub const fn extend(self, z: f32) -> Vec3

Creates a 3D vector from self and the given z value.

Examples found in repository?
examples/sprite-adventure.rs (line 1713)
1700    fn draw_walker(&self, ctx: &mut FrameContext<'_, Keep>, ground: Vec3) {
1701        let step = if self.walk_ticks > 0 {
1702            (self.walk_ticks / TICKS_PER_WALK_FRAME) % WALKER_COLUMNS
1703        } else {
1704            0
1705        };
1706        let cell = Sheet::new(UVec2::new(WALKER_COLUMNS, WALKER_ROWS))
1707            .cell_at(UVec2::new(step, self.facing as u32));
1708        let size = Vec2::new(WALKER_WIDTH, WALKER_HEIGHT);
1709
1710        ctx.draw(
1711            Walker
1712                .at(Transform::from_scale_rotation_translation(
1713                    size.extend(1.0),
1714                    Quat::IDENTITY,
1715                    ground + Vec3::Y * (WALKER_HEIGHT * 0.5),
1716                ))
1717                .upright()
1718                .frame(cell),
1719        );
1720    }
Source

pub fn with_x(self, x: f32) -> Vec2

Creates a 2D vector from self with the given value of x.

Source

pub fn with_y(self, y: f32) -> Vec2

Creates a 2D vector from self with the given value of y.

Source

pub fn dot(self, rhs: Vec2) -> f32

Computes the dot product of self and rhs.

Source

pub fn dot_into_vec(self, rhs: Vec2) -> Vec2

Returns a vector where every component is the dot product of self and rhs.

Source

pub fn min(self, rhs: Vec2) -> Vec2

Returns a vector containing the minimum values for each element of self and rhs.

In other words this computes [min(x, rhs.x), min(self.y, rhs.y), ..].

NaN propogation does not follow IEEE 754-2008 semantics for minNum and may differ on different SIMD architectures.

Examples found in repository?
examples/sprite-adventure.rs (line 469)
467    fn over(corners: [Vec2; 4]) -> Self {
468        let [first, rest @ ..] = corners;
469        let low = rest.iter().fold(first, |low, &corner| low.min(corner));
470        let high = rest.iter().fold(first, |high, &corner| high.max(corner));
471
472        Self {
473            center: (low + high) * 0.5,
474            half: (high - low) * 0.5,
475        }
476    }
Source

pub fn max(self, rhs: Vec2) -> Vec2

Returns a vector containing the maximum values for each element of self and rhs.

In other words this computes [max(self.x, rhs.x), max(self.y, rhs.y), ..].

NaN propogation does not follow IEEE 754-2008 semantics for maxNum and may differ on different SIMD architectures.

Examples found in repository?
examples/sprite-adventure.rs (line 470)
467    fn over(corners: [Vec2; 4]) -> Self {
468        let [first, rest @ ..] = corners;
469        let low = rest.iter().fold(first, |low, &corner| low.min(corner));
470        let high = rest.iter().fold(first, |high, &corner| high.max(corner));
471
472        Self {
473            center: (low + high) * 0.5,
474            half: (high - low) * 0.5,
475        }
476    }
Source

pub fn clamp(self, min: Vec2, max: Vec2) -> Vec2

Component-wise clamping of values, similar to f32::clamp.

Each element in min must be less-or-equal to the corresponding element in max.

NaN propogation does not follow IEEE 754-2008 semantics and may differ on different SIMD architectures.

§Panics

Will panic if min is greater than max when glam_assert is enabled.

Examples found in repository?
examples/sound-lab.rs (line 469)
461    fn handle_walk(&mut self, ctx: &mut TickContext<'_, SoundCheck>) {
462        self.player_prev = self.player;
463        if ctx.ui_wants_keyboard() {
464            return;
465        }
466        let walk = ctx.axis2(Move::Walk);
467        let world = Vec2::new(walk.x, -walk.y);
468        self.player = (self.player + world * WALK_SPEED * ctx.dt().as_secs_f32())
469            .clamp(Vec2::splat(-PLAY_BOUND), Vec2::splat(PLAY_BOUND));
470    }
471
472    /// Takes hold of the source a click's ray intersects, moves it across
473    /// the floor while the button stays down, and frees it on release.
474    fn handle_drag(&mut self, ctx: &mut TickContext<'_, SoundCheck>) {
475        // Read before the check below for the UI's own claim on the
476        // pointer, so a release over it still frees a source a drag moved
477        // there.
478        if ctx.released(Button::Select) {
479            self.dragging = None;
480        }
481        if ctx.ui_wants_pointer() {
482            return;
483        }
484        let ray = ctx
485            .last_camera()
486            .ray_through(ctx.pointer(), ctx.window_size());
487
488        if ctx.pressed(Button::Select) {
489            self.dragging = self.sources.iter().position(|source| {
490                ray.hit_sphere(source.position, SOURCE_PICK_RADIUS)
491                    .is_some()
492            });
493        }
494
495        let Some(index) = self.dragging else {
496            return;
497        };
498        let Some(distance) = ray.hit_plane(ray::Plane {
499            point: Vec3::ZERO,
500            normal: Vec3::Y,
501        }) else {
502            return;
503        };
504        let hit = ray.at(distance);
505        let dropped =
506            Vec2::new(hit.x, hit.z).clamp(Vec2::splat(-PLAY_BOUND), Vec2::splat(PLAY_BOUND));
507        self.sources[index].position = Vec3::new(dropped.x, SOURCE_HEIGHT, dropped.y);
508    }
Source

pub fn min_element(self) -> f32

Returns the horizontal minimum of self.

In other words this computes min(x, y, ..).

NaN propogation does not follow IEEE 754-2008 semantics and may differ on different SIMD architectures.

Examples found in repository?
examples/sprite-adventure.rs (line 484)
480    fn push_out(self, point: Vec2, radius: f32) -> Vec2 {
481        let delta = point - self.center;
482        let escape = self.half + Vec2::splat(radius) - delta.abs();
483
484        if escape.min_element() <= 0.0 {
485            point
486        } else if escape.x < escape.y {
487            let x = self.center.x + delta.x.signum() * (self.half.x + radius);
488            Vec2::new(x, point.y)
489        } else {
490            let z = self.center.y + delta.y.signum() * (self.half.y + radius);
491            Vec2::new(point.x, z)
492        }
493    }
Source

pub fn max_element(self) -> f32

Returns the horizontal maximum of self.

In other words this computes max(x, y, ..).

NaN propogation does not follow IEEE 754-2008 semantics and may differ on different SIMD architectures.

Source

pub fn min_position(self) -> usize

Returns the index of the first minimum element of self.

Source

pub fn max_position(self) -> usize

Returns the index of the first maximum element of self.

Source

pub fn element_sum(self) -> f32

Returns the sum of all elements of self.

In other words, this computes self.x + self.y + ...

Source

pub fn element_product(self) -> f32

Returns the product of all elements of self.

In other words, this computes self.x * self.y * ...

Source

pub fn cmpeq(self, rhs: Vec2) -> BVec2

Returns a vector mask containing the result of a == comparison for each element of self and rhs.

In other words, this computes [self.x == rhs.x, self.y == rhs.y, ..] for all elements.

Source

pub fn cmpne(self, rhs: Vec2) -> BVec2

Returns a vector mask containing the result of a != comparison for each element of self and rhs.

In other words this computes [self.x != rhs.x, self.y != rhs.y, ..] for all elements.

Source

pub fn cmpge(self, rhs: Vec2) -> BVec2

Returns a vector mask containing the result of a >= comparison for each element of self and rhs.

In other words this computes [self.x >= rhs.x, self.y >= rhs.y, ..] for all elements.

Source

pub fn cmpgt(self, rhs: Vec2) -> BVec2

Returns a vector mask containing the result of a > comparison for each element of self and rhs.

In other words this computes [self.x > rhs.x, self.y > rhs.y, ..] for all elements.

Source

pub fn cmple(self, rhs: Vec2) -> BVec2

Returns a vector mask containing the result of a <= comparison for each element of self and rhs.

In other words this computes [self.x <= rhs.x, self.y <= rhs.y, ..] for all elements.

Source

pub fn cmplt(self, rhs: Vec2) -> BVec2

Returns a vector mask containing the result of a < comparison for each element of self and rhs.

In other words this computes [self.x < rhs.x, self.y < rhs.y, ..] for all elements.

Source

pub fn abs(self) -> Vec2

Returns a vector containing the absolute value of each element of self.

Examples found in repository?
examples/sprite-adventure.rs (line 482)
480    fn push_out(self, point: Vec2, radius: f32) -> Vec2 {
481        let delta = point - self.center;
482        let escape = self.half + Vec2::splat(radius) - delta.abs();
483
484        if escape.min_element() <= 0.0 {
485            point
486        } else if escape.x < escape.y {
487            let x = self.center.x + delta.x.signum() * (self.half.x + radius);
488            Vec2::new(x, point.y)
489        } else {
490            let z = self.center.y + delta.y.signum() * (self.half.y + radius);
491            Vec2::new(point.x, z)
492        }
493    }
Source

pub fn signum(self) -> Vec2

Returns a vector with elements representing the sign of self.

  • 1.0 if the number is positive, +0.0 or INFINITY
  • -1.0 if the number is negative, -0.0 or NEG_INFINITY
  • NAN if the number is NAN
Source

pub fn copysign(self, rhs: Vec2) -> Vec2

Returns a vector with signs of rhs and the magnitudes of self.

Source

pub fn is_negative_bitmask(self) -> u32

Returns a bitmask with the lowest 2 bits set to the sign bits from the elements of self.

A negative element results in a 1 bit and a positive element in a 0 bit. Element x goes into the first lowest bit, element y into the second, etc.

An element is negative if it has a negative sign, including -0.0, NaNs with negative sign bit and negative infinity.

Source

pub fn is_negative_mask(self) -> BVec2

Returns a mask indicating which components are negative.

An element is negative if it has a negative sign, including -0.0, NaNs with negative sign bit and negative infinity.

Source

pub fn is_finite(self) -> bool

Returns true if, and only if, all elements are finite. If any element is either NaN, positive or negative infinity, this will return false.

Source

pub fn is_finite_mask(self) -> BVec2

Performs is_finite on each element of self, returning a vector mask of the results.

In other words, this computes [x.is_finite(), y.is_finite(), ...].

Source

pub fn is_nan(self) -> bool

Returns true if any elements are NaN.

Source

pub fn is_nan_mask(self) -> BVec2

Performs is_nan on each element of self, returning a vector mask of the results.

In other words, this computes [x.is_nan(), y.is_nan(), ...].

Source

pub fn length(self) -> f32

Computes the length of self.

Source

pub fn length_squared(self) -> f32

Computes the squared length of self.

This is faster than length() as it avoids a square root operation.

Source

pub fn length_recip(self) -> f32

Computes 1.0 / length().

For valid results, self must not be of length zero.

Source

pub fn distance(self, rhs: Vec2) -> f32

Computes the Euclidean distance between two points in space.

Source

pub fn distance_squared(self, rhs: Vec2) -> f32

Compute the squared euclidean distance between two points in space.

Source

pub fn div_euclid(self, rhs: Vec2) -> Vec2

Returns the element-wise quotient of [Euclidean division] of self by rhs.

Source

pub fn rem_euclid(self, rhs: Vec2) -> Vec2

Returns the element-wise remainder of Euclidean division of self by rhs.

Source

pub fn normalize(self) -> Vec2

Returns self normalized to length 1.0.

For valid results, self must be finite and not of length zero, nor very close to zero.

See also Self::try_normalize() and Self::normalize_or_zero().

§Panics

Will panic if the resulting normalized vector is not finite when glam_assert is enabled.

Source

pub fn try_normalize(self) -> Option<Vec2>

Returns self normalized to length 1.0 if possible, else returns None.

In particular, if the input is zero (or very close to zero), or non-finite, the result of this operation will be None.

See also Self::normalize_or_zero().

Source

pub fn normalize_or(self, fallback: Vec2) -> Vec2

Returns self normalized to length 1.0 if possible, else returns a fallback value.

In particular, if the input is zero (or very close to zero), or non-finite, the result of this operation will be the fallback value.

See also Self::try_normalize().

Source

pub fn normalize_or_zero(self) -> Vec2

Returns self normalized to length 1.0 if possible, else returns zero.

In particular, if the input is zero (or very close to zero), or non-finite, the result of this operation will be zero.

See also Self::try_normalize().

Source

pub fn normalize_and_length(self) -> (Vec2, f32)

Returns self normalized to length 1.0 and the length of self.

If self is zero length then (Self::X, 0.0) is returned.

Source

pub fn is_normalized(self) -> bool

Returns whether self is length 1.0 or not.

Uses a precision threshold of approximately 1e-4.

Source

pub fn project_onto(self, rhs: Vec2) -> Vec2

Returns the vector projection of self onto rhs.

rhs must be of non-zero length.

§Panics

Will panic if rhs is zero length when glam_assert is enabled.

Source

pub fn reject_from(self, rhs: Vec2) -> Vec2

Returns the vector rejection of self from rhs.

The vector rejection is the vector perpendicular to the projection of self onto rhs, in rhs words the result of self - self.project_onto(rhs).

rhs must be of non-zero length.

§Panics

Will panic if rhs has a length of zero when glam_assert is enabled.

Source

pub fn project_onto_normalized(self, rhs: Vec2) -> Vec2

Returns the vector projection of self onto rhs.

rhs must be normalized.

§Panics

Will panic if rhs is not normalized when glam_assert is enabled.

Source

pub fn reject_from_normalized(self, rhs: Vec2) -> Vec2

Returns the vector rejection of self from rhs.

The vector rejection is the vector perpendicular to the projection of self onto rhs, in rhs words the result of self - self.project_onto(rhs).

rhs must be normalized.

§Panics

Will panic if rhs is not normalized when glam_assert is enabled.

Source

pub fn round(self) -> Vec2

Returns a vector containing the nearest integer to a number for each element of self. Round half-way cases away from 0.0.

Source

pub fn floor(self) -> Vec2

Returns a vector containing the largest integer less than or equal to a number for each element of self.

Source

pub fn ceil(self) -> Vec2

Returns a vector containing the smallest integer greater than or equal to a number for each element of self.

Source

pub fn trunc(self) -> Vec2

Returns a vector containing the integer part each element of self. This means numbers are always truncated towards zero.

Source

pub fn step(self, rhs: Vec2) -> Vec2

Returns a vector containing 0.0 if rhs < self and 1.0 otherwise.

Similar to glsl’s step(edge, x), which translates into edge.step(x)

Source

pub fn saturate(self) -> Vec2

Returns a vector containing all elements of self clamped to the range of [0, 1].

Source

pub fn fract(self) -> Vec2

Returns a vector containing the fractional part of the vector as self - self.trunc().

Note that this differs from the GLSL implementation of fract which returns self - self.floor().

Note that this is fast but not precise for large numbers.

Source

pub fn fract_gl(self) -> Vec2

Returns a vector containing the fractional part of the vector as self - self.floor().

Note that this differs from the Rust implementation of fract which returns self - self.trunc().

Note that this is fast but not precise for large numbers.

Source

pub fn exp(self) -> Vec2

Returns a vector containing e^self (the exponential function) for each element of self.

Source

pub fn exp2(self) -> Vec2

Returns a vector containing 2^self for each element of self.

Source

pub fn ln(self) -> Vec2

Returns a vector containing the natural logarithm for each element of self. This returns NaN when the element is negative and negative infinity when the element is zero.

Source

pub fn log2(self) -> Vec2

Returns a vector containing the base 2 logarithm for each element of self. This returns NaN when the element is negative and negative infinity when the element is zero.

Source

pub fn powf(self, n: f32) -> Vec2

Returns a vector containing each element of self raised to the power of n.

Source

pub fn sqrt(self) -> Vec2

Returns a vector containing the square root for each element of self. This returns NaN when the element is negative.

Source

pub fn cos(self) -> Vec2

Returns a vector containing the cosine for each element of self.

Source

pub fn sin(self) -> Vec2

Returns a vector containing the sine for each element of self.

Source

pub fn sin_cos(self) -> (Vec2, Vec2)

Returns a tuple of two vectors containing the sine and cosine for each element of self.

Source

pub fn recip(self) -> Vec2

Returns a vector containing the reciprocal 1.0/n of each element of self.

Source

pub fn lerp(self, rhs: Vec2, s: f32) -> Vec2

Performs a linear interpolation between self and rhs based on the value s.

When s is 0.0, the result will be equal to self. When s is 1.0, the result will be equal to rhs. When s is outside of range [0, 1], the result is linearly extrapolated.

Examples found in repository?
examples/sound-lab.rs (line 981)
978    fn frame(&mut self, ctx: &mut FrameContext<'_, SoundCheck>) {
979        ctx.set_volume(self.master_volume);
980
981        let player = self.player_prev.lerp(self.player, ctx.alpha());
982        let ear = Vec3::new(player.x, EYE_HEIGHT, player.y);
983        let listener = View::look_at(ear, ear + Vec3::NEG_Z);
984        ctx.set_listener(listener);
985
986        ctx.set_camera(Self::camera(player));
987        ctx.set_skybox(Sky::Room);
988        ctx.set_bloom(0.2);
989        ctx.light(Light::directional(Vec3::new(-0.4, -1.0, -0.5), SUN_COLOR).shadow());
990
991        self.draw_room(ctx);
992        self.draw_sources(ctx);
993        self.draw_listener(ctx, listener);
994        self.draw_merge_markers(ctx);
995        self.draw_ring(ctx);
996
997        self.sustain_cues(ctx);
998        for (index, source) in self.sources.iter().enumerate() {
999            if source.enabled {
1000                ctx.sustain(source.cue().instance(index as u32));
1001            }
1002        }
1003        if self.merge_demo {
1004            ctx.sustain(Sound::Click.at(MERGE_POS_A).gain(MERGE_GAIN));
1005            ctx.sustain(Sound::Click.at(MERGE_POS_B).gain(MERGE_GAIN));
1006        }
1007        self.sustain_ring(ctx);
1008
1009        self.side_panel(ctx);
1010        let (play_once, play_many) = self.one_shot_panel(ctx);
1011
1012        if play_once {
1013            ctx.play(self.one_shot_cue());
1014        }
1015        if play_many {
1016            for _ in 0..32 {
1017                ctx.play(self.one_shot_cue());
1018            }
1019        }
1020    }
Source

pub fn move_towards(self, rhs: Vec2, d: f32) -> Vec2

Moves towards rhs based on the value d.

When d is 0.0, the result will be equal to self. When d is equal to self.distance(rhs), the result will be equal to rhs. Will not go past rhs.

Source

pub fn midpoint(self, rhs: Vec2) -> Vec2

Calculates the midpoint between self and rhs.

The midpoint is the average of, or halfway point between, two vectors. a.midpoint(b) should yield the same result as a.lerp(b, 0.5) while being slightly cheaper to compute.

Source

pub fn abs_diff_eq(self, rhs: Vec2, max_abs_diff: f32) -> bool

Returns true if the absolute difference of all elements between self and rhs is less than or equal to max_abs_diff.

This can be used to compare if two vectors contain similar elements. It works best when comparing with a known value. The max_abs_diff that should be used used depends on the values being compared against.

For more see comparing floating point numbers.

Source

pub fn clamp_length(self, min: f32, max: f32) -> Vec2

Returns a vector with a length no less than min and no more than max.

§Panics

Will panic if min is greater than max, or if either min or max is negative, when glam_assert is enabled.

Source

pub fn clamp_length_max(self, max: f32) -> Vec2

Returns a vector with a length no more than max.

§Panics

Will panic if max is negative when glam_assert is enabled.

Examples found in repository?
examples/animation.rs (line 693)
692    fn advance(&mut self, ctx: &mut TickContext<'_, Scene>) -> f32 {
693        let control = ctx.axis2(Move::Walk).clamp_length_max(1.0);
694        let turn = Quat::from_rotation_y(self.camera_yaw);
695        let heading = turn * Vec3::X * control.x + turn * Vec3::NEG_Z * control.y;
696        let dt = ctx.dt().as_secs_f32();
697        if let Some(direction) = heading.try_normalize() {
698            let wanted = direction.x.atan2(direction.z);
699            let turn = (wanted - self.elf_yaw + core::f32::consts::PI).rem_euclid(TAU)
700                - core::f32::consts::PI;
701            self.elf_yaw += turn.clamp(-TURN_RATE * dt, TURN_RATE * dt);
702        }
703        let cap = if ctx.down(Button::Run) { 1.0 } else { WALK_CAP };
704        self.elf_pos += heading * cap * ELF_SPEED * dt;
705        heading.length() * cap
706    }
More examples
Hide additional examples
examples/input-lab.rs (line 497)
486fn axis2_dot(ui: &mut egui::Ui, value: Vec2) {
487    let square_side = 36.0;
488    let radius = 4.0;
489    let (column, _response) = ui.allocate_exact_size(
490        egui::vec2(VALUE_COLUMN_WIDTH, square_side),
491        egui::Sense::hover(),
492    );
493    let rect = egui::Rect::from_center_size(column.center(), egui::Vec2::splat(square_side));
494    let painter = ui.painter();
495    painter.rect_filled(rect, 2.0, egui::Color32::from_gray(35));
496
497    let shown = value.clamp_length_max(1.0);
498    let reach = rect.width() * 0.5 - READING_MARGIN - radius;
499    let point = rect.center() + egui::vec2(shown.x, -shown.y) * reach;
500    painter.circle_filled(point, radius, highlight_color(value != Vec2::ZERO));
501    painter.rect_stroke(
502        rect,
503        2.0,
504        egui::Stroke::new(1.0, egui::Color32::from_gray(120)),
505        egui::StrokeKind::Inside,
506    );
507
508    ui.label(format!("{:.2}, {:.2}", value.x, value.y));
509}
Source

pub fn clamp_length_min(self, min: f32) -> Vec2

Returns a vector with a length no less than min.

§Panics

Will panic if min is negative when glam_assert is enabled.

Source

pub fn mul_add(self, a: Vec2, b: Vec2) -> Vec2

Fused multiply-add. Computes (self * a) + b element-wise with only one rounding error, yielding a more accurate result than an unfused multiply-add.

Using mul_add may be more performant than an unfused multiply-add if the target architecture has a dedicated fma CPU instruction. However, this is not always true, and will be heavily dependant on designing algorithms with specific target hardware in mind.

Source

pub fn reflect(self, normal: Vec2) -> Vec2

Returns the reflection vector for a given incident vector self and surface normal normal.

normal must be normalized.

§Panics

Will panic if normal is not normalized when glam_assert is enabled.

Source

pub fn refract(self, normal: Vec2, eta: f32) -> Vec2

Returns the refraction direction for a given incident vector self, surface normal normal and ratio of indices of refraction, eta. When total internal reflection occurs, a zero vector will be returned.

self and normal must be normalized.

§Panics

Will panic if self or normal is not normalized when glam_assert is enabled.

Source

pub fn from_angle(angle: f32) -> Vec2

Creates a 2D vector containing [angle.cos(), angle.sin()]. This can be used in conjunction with the rotate() method, e.g. Vec2::from_angle(PI).rotate(Vec2::Y) will create the vector [-1, 0] and rotate Vec2::Y around it returning -Vec2::Y.

Source

pub fn to_angle(self) -> f32

Returns the angle (in radians) of this vector in the range [-π, +π].

The input does not need to be a unit vector however it must be non-zero.

Source

pub fn angle_to(self, rhs: Vec2) -> f32

Returns the angle of rotation (in radians) from self to rhs in the range [-π, +π].

The inputs do not need to be unit vectors however they must be non-zero.

The returned angle can be used with rotate_angle(), e.g. self.rotate_angle(self.angle_to(rhs)) will be equal to rhs.

§Panics

Will panic if self or rhs has zero length when glam_assert is enabled.

Source

pub fn perp(self) -> Vec2

Returns a vector that is equal to self rotated by 90 degrees.

Source

pub fn perp_dot(self, rhs: Vec2) -> f32

The perpendicular dot product of self and rhs. Also known as the wedge product, 2D cross product, and determinant.

Source

pub fn rotate(self, rhs: Vec2) -> Vec2

Returns rhs rotated by the angle of self. If self is normalized, then this just rotation. This is what you usually want. Otherwise, it will be like a rotation with a multiplication by self’s length.

This can be used in conjunction with the from_angle() method, e.g. Vec2::from_angle(PI).rotate(Vec2::Y) will create the vector [-1, 0] and rotate Vec2::Y around it returning -Vec2::Y.

Source

pub fn rotate_angle(self, angle: f32) -> Vec2

Rotates self by angle (in radians), equivalent to self.rotate(Vec2::from_angle(angle)).

Source

pub fn rotate_towards(self, rhs: Vec2, max_angle: f32) -> Vec2

Rotates towards rhs up to max_angle (in radians).

When max_angle is 0.0, the result will be equal to self. When max_angle is equal to self.angle_between(rhs), the result will be parallel to rhs. If max_angle is negative, rotates towards the exact opposite of rhs. Will not go past the target.

Source

pub fn as_dvec2(self) -> DVec2

Casts all elements of self to f64.

Source

pub fn as_i8vec2(self) -> I8Vec2

Casts all elements of self to i8.

Source

pub fn as_u8vec2(self) -> U8Vec2

Casts all elements of self to u8.

Source

pub fn as_i16vec2(self) -> I16Vec2

Casts all elements of self to i16.

Source

pub fn as_u16vec2(self) -> U16Vec2

Casts all elements of self to u16.

Source

pub fn as_ivec2(self) -> IVec2

Casts all elements of self to i32.

Source

pub fn as_uvec2(self) -> UVec2

Casts all elements of self to u32.

Source

pub fn as_i64vec2(self) -> I64Vec2

Casts all elements of self to i64.

Source

pub fn as_u64vec2(self) -> U64Vec2

Casts all elements of self to u64.

Source

pub fn as_isizevec2(self) -> ISizeVec2

Casts all elements of self to isize.

Source

pub fn as_usizevec2(self) -> USizeVec2

Casts all elements of self to usize.

Trait Implementations§

Source§

impl Add for Vec2

Source§

type Output = Vec2

The resulting type after applying the + operator.
Source§

fn add(self, rhs: Vec2) -> Vec2

Performs the + operation. Read more
Source§

impl Add<&Vec2> for Vec2

Source§

type Output = Vec2

The resulting type after applying the + operator.
Source§

fn add(self, rhs: &Vec2) -> Vec2

Performs the + operation. Read more
Source§

impl Add<&Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the + operator.
Source§

fn add(self, rhs: &Vec2) -> Vec2

Performs the + operation. Read more
Source§

impl Add<&f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the + operator.
Source§

fn add(self, rhs: &f32) -> Vec2

Performs the + operation. Read more
Source§

impl Add<&f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the + operator.
Source§

fn add(self, rhs: &f32) -> Vec2

Performs the + operation. Read more
Source§

impl Add<Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the + operator.
Source§

fn add(self, rhs: Vec2) -> Vec2

Performs the + operation. Read more
Source§

impl Add<f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the + operator.
Source§

fn add(self, rhs: f32) -> Vec2

Performs the + operation. Read more
Source§

impl Add<f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the + operator.
Source§

fn add(self, rhs: f32) -> Vec2

Performs the + operation. Read more
Source§

impl AddAssign for Vec2

Source§

fn add_assign(&mut self, rhs: Vec2)

Performs the += operation. Read more
Source§

impl AddAssign<&Vec2> for Vec2

Source§

fn add_assign(&mut self, rhs: &Vec2)

Performs the += operation. Read more
Source§

impl AddAssign<&f32> for Vec2

Source§

fn add_assign(&mut self, rhs: &f32)

Performs the += operation. Read more
Source§

impl AddAssign<f32> for Vec2

Source§

fn add_assign(&mut self, rhs: f32)

Performs the += operation. Read more
Source§

impl AsMut<[f32; 2]> for Vec2

Source§

fn as_mut(&mut self) -> &mut [f32; 2]

Converts this type into a mutable reference of the (usually inferred) input type.
Source§

impl AsRef<[f32; 2]> for Vec2

Source§

fn as_ref(&self) -> &[f32; 2]

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl Clone for Vec2

Source§

fn clone(&self) -> Vec2

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Vec2

Source§

impl Debug for Vec2

Source§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for Vec2

Source§

fn default() -> Vec2

Returns the “default value” for a type. Read more
Source§

impl Display for Vec2

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Div for Vec2

Source§

type Output = Vec2

The resulting type after applying the / operator.
Source§

fn div(self, rhs: Vec2) -> Vec2

Performs the / operation. Read more
Source§

impl Div<&Vec2> for Vec2

Source§

type Output = Vec2

The resulting type after applying the / operator.
Source§

fn div(self, rhs: &Vec2) -> Vec2

Performs the / operation. Read more
Source§

impl Div<&Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the / operator.
Source§

fn div(self, rhs: &Vec2) -> Vec2

Performs the / operation. Read more
Source§

impl Div<&f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the / operator.
Source§

fn div(self, rhs: &f32) -> Vec2

Performs the / operation. Read more
Source§

impl Div<&f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the / operator.
Source§

fn div(self, rhs: &f32) -> Vec2

Performs the / operation. Read more
Source§

impl Div<Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the / operator.
Source§

fn div(self, rhs: Vec2) -> Vec2

Performs the / operation. Read more
Source§

impl Div<f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the / operator.
Source§

fn div(self, rhs: f32) -> Vec2

Performs the / operation. Read more
Source§

impl Div<f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the / operator.
Source§

fn div(self, rhs: f32) -> Vec2

Performs the / operation. Read more
Source§

impl DivAssign for Vec2

Source§

fn div_assign(&mut self, rhs: Vec2)

Performs the /= operation. Read more
Source§

impl DivAssign<&Vec2> for Vec2

Source§

fn div_assign(&mut self, rhs: &Vec2)

Performs the /= operation. Read more
Source§

impl DivAssign<&f32> for Vec2

Source§

fn div_assign(&mut self, rhs: &f32)

Performs the /= operation. Read more
Source§

impl DivAssign<f32> for Vec2

Source§

fn div_assign(&mut self, rhs: f32)

Performs the /= operation. Read more
Source§

impl From<(f32, f32)> for Vec2

Source§

fn from(t: (f32, f32)) -> Vec2

Converts to this type from the input type.
Source§

impl From<BVec2> for Vec2

Source§

fn from(v: BVec2) -> Vec2

Converts to this type from the input type.
Source§

impl From<Vec2> for DVec2

Source§

fn from(v: Vec2) -> DVec2

Converts to this type from the input type.
Source§

impl From<[f32; 2]> for Vec2

Source§

fn from(a: [f32; 2]) -> Vec2

Converts to this type from the input type.
Source§

impl Index<usize> for Vec2

Source§

type Output = f32

The returned type after indexing.
Source§

fn index(&self, index: usize) -> &<Vec2 as Index<usize>>::Output

Performs the indexing (container[index]) operation. Read more
Source§

impl IndexMut<usize> for Vec2

Source§

fn index_mut(&mut self, index: usize) -> &mut <Vec2 as Index<usize>>::Output

Performs the mutable indexing (container[index]) operation. Read more
Source§

impl Mul for Vec2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Vec2) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<&Vec2> for Vec2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: &Vec2) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<&Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: &Vec2) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<&Vec2> for Mat2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: &Vec2) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<&Vec2> for &Mat2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: &Vec2) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<&f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: &f32) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<&f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: &f32) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Vec2) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<Vec2> for Mat2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Vec2) -> <Mat2 as Mul<Vec2>>::Output

Performs the * operation. Read more
Source§

impl Mul<Vec2> for &Mat2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Vec2) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: f32) -> Vec2

Performs the * operation. Read more
Source§

impl Mul<f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: f32) -> Vec2

Performs the * operation. Read more
Source§

impl MulAssign for Vec2

Source§

fn mul_assign(&mut self, rhs: Vec2)

Performs the *= operation. Read more
Source§

impl MulAssign<&Vec2> for Vec2

Source§

fn mul_assign(&mut self, rhs: &Vec2)

Performs the *= operation. Read more
Source§

impl MulAssign<&f32> for Vec2

Source§

fn mul_assign(&mut self, rhs: &f32)

Performs the *= operation. Read more
Source§

impl MulAssign<f32> for Vec2

Source§

fn mul_assign(&mut self, rhs: f32)

Performs the *= operation. Read more
Source§

impl Neg for Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn neg(self) -> Vec2

Performs the unary - operation. Read more
Source§

impl Neg for &Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn neg(self) -> Vec2

Performs the unary - operation. Read more
Source§

impl PartialEq for Vec2

Source§

fn eq(&self, other: &Vec2) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Pod for Vec2

Source§

impl Product for Vec2

Source§

fn product<I>(iter: I) -> Vec2
where I: Iterator<Item = Vec2>,

Takes an iterator and generates Self from the elements by multiplying the items.
Source§

impl<'a> Product<&'a Vec2> for Vec2

Source§

fn product<I>(iter: I) -> Vec2
where I: Iterator<Item = &'a Vec2>,

Takes an iterator and generates Self from the elements by multiplying the items.
Source§

impl Rem for Vec2

Source§

type Output = Vec2

The resulting type after applying the % operator.
Source§

fn rem(self, rhs: Vec2) -> Vec2

Performs the % operation. Read more
Source§

impl Rem<&Vec2> for Vec2

Source§

type Output = Vec2

The resulting type after applying the % operator.
Source§

fn rem(self, rhs: &Vec2) -> Vec2

Performs the % operation. Read more
Source§

impl Rem<&Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the % operator.
Source§

fn rem(self, rhs: &Vec2) -> Vec2

Performs the % operation. Read more
Source§

impl Rem<&f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the % operator.
Source§

fn rem(self, rhs: &f32) -> Vec2

Performs the % operation. Read more
Source§

impl Rem<&f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the % operator.
Source§

fn rem(self, rhs: &f32) -> Vec2

Performs the % operation. Read more
Source§

impl Rem<Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the % operator.
Source§

fn rem(self, rhs: Vec2) -> Vec2

Performs the % operation. Read more
Source§

impl Rem<f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the % operator.
Source§

fn rem(self, rhs: f32) -> Vec2

Performs the % operation. Read more
Source§

impl Rem<f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the % operator.
Source§

fn rem(self, rhs: f32) -> Vec2

Performs the % operation. Read more
Source§

impl RemAssign for Vec2

Source§

fn rem_assign(&mut self, rhs: Vec2)

Performs the %= operation. Read more
Source§

impl RemAssign<&Vec2> for Vec2

Source§

fn rem_assign(&mut self, rhs: &Vec2)

Performs the %= operation. Read more
Source§

impl RemAssign<&f32> for Vec2

Source§

fn rem_assign(&mut self, rhs: &f32)

Performs the %= operation. Read more
Source§

impl RemAssign<f32> for Vec2

Source§

fn rem_assign(&mut self, rhs: f32)

Performs the %= operation. Read more
Source§

impl StructuralPartialEq for Vec2

Source§

impl Sub for Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: Vec2) -> Vec2

Performs the - operation. Read more
Source§

impl Sub<&Vec2> for Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: &Vec2) -> Vec2

Performs the - operation. Read more
Source§

impl Sub<&Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: &Vec2) -> Vec2

Performs the - operation. Read more
Source§

impl Sub<&f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: &f32) -> Vec2

Performs the - operation. Read more
Source§

impl Sub<&f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: &f32) -> Vec2

Performs the - operation. Read more
Source§

impl Sub<Vec2> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: Vec2) -> Vec2

Performs the - operation. Read more
Source§

impl Sub<f32> for Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: f32) -> Vec2

Performs the - operation. Read more
Source§

impl Sub<f32> for &Vec2

Source§

type Output = Vec2

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: f32) -> Vec2

Performs the - operation. Read more
Source§

impl SubAssign for Vec2

Source§

fn sub_assign(&mut self, rhs: Vec2)

Performs the -= operation. Read more
Source§

impl SubAssign<&Vec2> for Vec2

Source§

fn sub_assign(&mut self, rhs: &Vec2)

Performs the -= operation. Read more
Source§

impl SubAssign<&f32> for Vec2

Source§

fn sub_assign(&mut self, rhs: &f32)

Performs the -= operation. Read more
Source§

impl SubAssign<f32> for Vec2

Source§

fn sub_assign(&mut self, rhs: f32)

Performs the -= operation. Read more
Source§

impl Sum for Vec2

Source§

fn sum<I>(iter: I) -> Vec2
where I: Iterator<Item = Vec2>,

Takes an iterator and generates Self from the elements by “summing up” the items.
Source§

impl<'a> Sum<&'a Vec2> for Vec2

Source§

fn sum<I>(iter: I) -> Vec2
where I: Iterator<Item = &'a Vec2>,

Takes an iterator and generates Self from the elements by “summing up” the items.
Source§

impl Vec2Swizzles for Vec2

Source§

type Vec3 = Vec3

Source§

type Vec4 = Vec4

Source§

fn xx(self) -> Vec2

Source§

fn yx(self) -> Vec2

Source§

fn yy(self) -> Vec2

Source§

fn xxx(self) -> Vec3

Source§

fn xxy(self) -> Vec3

Source§

fn xyx(self) -> Vec3

Source§

fn xyy(self) -> Vec3

Source§

fn yxx(self) -> Vec3

Source§

fn yxy(self) -> Vec3

Source§

fn yyx(self) -> Vec3

Source§

fn yyy(self) -> Vec3

Source§

fn xxxx(self) -> Vec4

Source§

fn xxxy(self) -> Vec4

Source§

fn xxyx(self) -> Vec4

Source§

fn xxyy(self) -> Vec4

Source§

fn xyxx(self) -> Vec4

Source§

fn xyxy(self) -> Vec4

Source§

fn xyyx(self) -> Vec4

Source§

fn xyyy(self) -> Vec4

Source§

fn yxxx(self) -> Vec4

Source§

fn yxxy(self) -> Vec4

Source§

fn yxyx(self) -> Vec4

Source§

fn yxyy(self) -> Vec4

Source§

fn yyxx(self) -> Vec4

Source§

fn yyxy(self) -> Vec4

Source§

fn yyyx(self) -> Vec4

Source§

fn yyyy(self) -> Vec4

Source§

fn xy(self) -> Self

Source§

impl Zeroable for Vec2

Source§

fn zeroed() -> Self

Auto Trait Implementations§

§

impl Freeze for Vec2

§

impl RefUnwindSafe for Vec2

§

impl Send for Vec2

§

impl Sync for Vec2

§

impl Unpin for Vec2

§

impl UnsafeUnpin for Vec2

§

impl UnwindSafe for Vec2

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> AnyBitPattern for T
where T: Pod,

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CheckedBitPattern for T
where T: AnyBitPattern,

Source§

type Bits = T

Self must have the same layout as the specified Bits except for the possible invalid bit patterns being checked during is_valid_bit_pattern.
Source§

fn is_valid_bit_pattern(_bits: &T) -> bool

If this function returns true, then it must be valid to reinterpret bits as &Self.
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> NoUninit for T
where T: Pod,

Source§

impl<T, Rhs> NumAssignOps<Rhs> for T
where T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>,

Source§

impl<T, Rhs, Output> NumOps<Rhs, Output> for T
where T: Sub<Rhs, Output = Output> + Mul<Rhs, Output = Output> + Div<Rhs, Output = Output> + Add<Rhs, Output = Output> + Rem<Rhs, Output = Output>,

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, Base> RefNum<Base> for T
where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base>,

Source§

impl<T> SerializableAny for T
where T: 'static + Any + Clone + for<'a> Send + Sync,

Source§

impl<T, S> SimdFrom<T, S> for T
where S: Simd,

Source§

fn simd_from(_simd: S, value: T) -> T

Source§

impl<F, T, S> SimdInto<T, S> for F
where T: SimdFrom<F, S>, S: Simd,

Source§

fn simd_into(self, simd: S) -> T

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T> ToSmolStr for T
where T: Display + ?Sized,

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more