nightshade 0.13.2

A cross-platform data-oriented game engine.
Documentation
use openxr as xr;

pub struct XrFrameContext {
    pub frame_state: xr::FrameState,
    pub views: Vec<xr::View>,
    pub image_index: u32,
    pub player_position: nalgebra_glm::Vec3,
    pub player_yaw: f32,
}

impl XrFrameContext {
    pub fn view_matrix(&self, eye_index: usize) -> nalgebra_glm::Mat4 {
        let view = &self.views[eye_index];
        let pose = &view.pose;

        let rotation = {
            let orientation = pose.orientation;
            let flip_x = nalgebra_glm::quat_angle_axis(
                180.0_f32.to_radians(),
                &nalgebra_glm::vec3(1.0, 0.0, 0.0),
            );
            let openxr_quat =
                nalgebra_glm::quat(orientation.w, orientation.z, orientation.y, orientation.x);
            let player_rotation =
                nalgebra_glm::quat_angle_axis(self.player_yaw, &nalgebra_glm::vec3(0.0, 1.0, 0.0));
            player_rotation * flip_x * openxr_quat
        };

        let local_x = -pose.position.x;
        let local_z = -pose.position.z;
        let rotated_x = local_x * self.player_yaw.cos() + local_z * self.player_yaw.sin();
        let rotated_z = -local_x * self.player_yaw.sin() + local_z * self.player_yaw.cos();
        let translation = nalgebra_glm::vec3(rotated_x, pose.position.y, rotated_z);
        let eye = translation + self.player_position;
        let target =
            eye + nalgebra_glm::quat_rotate_vec3(&rotation, &nalgebra_glm::vec3(0.0, 0.0, 1.0));
        let up = nalgebra_glm::quat_rotate_vec3(&rotation, &nalgebra_glm::vec3(0.0, 1.0, 0.0));

        nalgebra_glm::look_at_rh(&eye, &target, &up)
    }

    pub fn projection_matrix(&self, eye_index: usize) -> nalgebra_glm::Mat4 {
        let view = &self.views[eye_index];
        let fov = &view.fov;

        let tan_left = fov.angle_left.tan();
        let tan_right = fov.angle_right.tan();
        let tan_up = fov.angle_up.tan();
        let tan_down = fov.angle_down.tan();

        let near = 0.1_f32;

        let tan_width = tan_right - tan_left;
        let tan_height = tan_up - tan_down;

        let a11 = 2.0 / tan_width;
        let a22 = 2.0 / tan_height;
        let a31 = (tan_right + tan_left) / tan_width;
        let a32 = (tan_up + tan_down) / tan_height;

        let mut proj = nalgebra_glm::Mat4::zeros();
        proj[(0, 0)] = a11;
        proj[(1, 1)] = a22;
        proj[(0, 2)] = a31;
        proj[(1, 2)] = a32;
        proj[(2, 2)] = 0.0;
        proj[(2, 3)] = near;
        proj[(3, 2)] = -1.0;

        proj
    }

    pub fn camera_position(&self, eye_index: usize) -> nalgebra_glm::Vec3 {
        let view = &self.views[eye_index];
        let pose = &view.pose;
        let local_x = -pose.position.x;
        let local_z = -pose.position.z;
        let rotated_x = local_x * self.player_yaw.cos() + local_z * self.player_yaw.sin();
        let rotated_z = -local_x * self.player_yaw.sin() + local_z * self.player_yaw.cos();
        let translation = nalgebra_glm::vec3(rotated_x, pose.position.y, rotated_z);
        translation + self.player_position
    }

    pub fn eye_count(&self) -> usize {
        self.views.len()
    }
}