mittens-engine 0.7.0

A Vulkan and OpenXR scene engine with ECS, reactive signals, and Meow Meow scripting
use crate::engine::ecs::ComponentId;
use crate::engine::ecs::component::Component;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum XrHandPreference {
    Default,
    Left,
    Right,
    Either,
}

impl Default for XrHandPreference {
    fn default() -> Self {
        Self::Default
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum XrAxisControl {
    LeftStick,
    RightStick,
    LeftTrigger,
    RightTrigger,
    LeftGrip,
    RightGrip,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum XrButtonControl {
    LeftTrigger,
    RightTrigger,
    LeftGrip,
    RightGrip,
    ButtonA,
    ButtonB,
    ButtonX,
    ButtonY,
}

#[derive(Debug, Clone)]
pub struct InputXRGamepadComponent {
    pub enabled: bool,
    pub hand: XrHandPreference,
    pub locomotion: bool,
    pub speed: f32,
    pub deadzone: f32,
    pub component_id: Option<ComponentId>,
}

impl InputXRGamepadComponent {
    pub fn new() -> Self {
        Self {
            enabled: true,
            hand: XrHandPreference::Default,
            locomotion: true,
            speed: 3.0,
            deadzone: 0.2,
            component_id: None,
        }
    }

    pub fn enabled(mut self, enabled: bool) -> Self {
        self.enabled = enabled;
        self
    }

    pub fn hand(mut self, hand: XrHandPreference) -> Self {
        self.hand = hand;
        self
    }

    pub fn locomotion(mut self) -> Self {
        self.locomotion = true;
        self
    }

    pub fn locomotion_enabled(mut self, enabled: bool) -> Self {
        self.locomotion = enabled;
        self
    }

    pub fn speed(mut self, speed: f32) -> Self {
        self.speed = speed;
        self
    }

    pub fn deadzone(mut self, deadzone: f32) -> Self {
        self.deadzone = deadzone;
        self
    }
}

impl Default for InputXRGamepadComponent {
    fn default() -> Self {
        Self::new()
    }
}

impl Component for InputXRGamepadComponent {
    fn name(&self) -> &'static str {
        "input_vr_gamepad"
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
        self
    }

    fn set_id(&mut self, component: ComponentId) {
        self.component_id = Some(component);
    }

    fn init(&mut self, emit: &mut dyn crate::engine::ecs::SignalEmitter, component: ComponentId) {
        self.component_id = Some(component);
        emit.push_intent_now(
            component,
            crate::engine::ecs::IntentValue::RegisterInputXrGamepad {
                component_id: component,
            },
        );
    }

    fn cleanup(
        &mut self,
        emit: &mut dyn crate::engine::ecs::SignalEmitter,
        component: ComponentId,
    ) {
        emit.push_intent_now(
            component,
            crate::engine::ecs::IntentValue::RemoveInputXrGamepad {
                component_id: component,
            },
        );
    }

    fn to_mms_ast(
        &self,
        _world: &crate::engine::ecs::World,
    ) -> crate::scripting::ast::ComponentExpression {
        use crate::engine::ecs::component::ce_helpers::*;

        let hand = match self.hand {
            XrHandPreference::Default => "default",
            XrHandPreference::Left => "left",
            XrHandPreference::Right => "right",
            XrHandPreference::Either => "either",
        };

        let mut ce = ce_call("InputXRGamepad", "new", vec![])
            .with_call("enabled", vec![b(self.enabled)])
            .with_call("hand", vec![s(hand)]);
        if !self.locomotion {
            ce = ce.with_call("locomotion", vec![b(false)]);
        }
        if (self.speed - 3.0).abs() > f32::EPSILON {
            ce = ce.with_call("speed", vec![num(self.speed as f64)]);
        }
        if (self.deadzone - 0.2).abs() > f32::EPSILON {
            ce = ce.with_call("deadzone", vec![num(self.deadzone as f64)]);
        }
        ce
    }
}