lotus_shared/axis.rs
1//! Logische Controller-Achsen und Force Feedback, getrennt von Tastenaktionen.
2//!
3//! Logical controller axes and force feedback, separate from button actions.
4
5use serde::{Deserialize, Serialize};
6
7/// Achsenwert ohne Belegung und Ruhelage eines zentrierten Gebers.
8///
9/// Axis value without a binding, and the rest position of a centered control.
10pub const AXIS_CENTER: f32 = 0.5;
11
12/// Beschreibt eine Achse, die bei der Engine registriert werden kann.
13///
14/// Describes an axis that can be registered with the engine.
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
16pub struct RegisterAxis {
17 /// Eindeutige Achsen-ID für Scripts und die Belegung.
18 ///
19 /// Unique axis identifier used by scripts and bindings.
20 pub id: String,
21}
22
23impl RegisterAxis {
24 /// Erstellt einen neuen Registrierungseintrag für eine Achse.
25 ///
26 /// Creates a new axis registration entry.
27 pub fn new(id: impl Into<String>) -> Self {
28 Self { id: id.into() }
29 }
30}
31
32/// Rückstellkraft einer Achse.
33///
34/// Restoring force of an axis.
35///
36/// `coefficient`, `saturation` und `offset` liegen in `0..=1`.
37/// `offset` 0 lässt die Federmitte unverändert.
38#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
39pub struct SpringForce {
40 /// Steifigkeit der Feder.
41 ///
42 /// Spring stiffness.
43 pub coefficient: f32,
44 /// Obere Grenze der Kraft.
45 ///
46 /// Upper bound of the force.
47 pub saturation: f32,
48 /// Verschiebung der Federmitte.
49 ///
50 /// Shift of the spring center.
51 pub offset: f32,
52}
53
54/// Schwingung entlang einer Achse.
55///
56/// Oscillation along an axis.
57#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
58pub struct AxisVibration {
59 /// Stärke, `0` schaltet die Schwingung aus.
60 ///
61 /// Strength; `0` turns the oscillation off.
62 pub magnitude: f32,
63 /// Frequenz in Hertz.
64 ///
65 /// Frequency in hertz.
66 pub frequency_hz: f32,
67}
68
69/// Zuletzt gewünschtes Force Feedback einer logischen Achse.
70///
71/// Latest requested force feedback for one logical axis.
72#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)]
73pub struct AxisForceFeedback {
74 /// Feder. `None`, solange das Script noch keine gesetzt hat.
75 ///
76 /// Spring. `None` until the script sets one.
77 pub spring: Option<SpringForce>,
78 /// Reibung, `0` heißt aus.
79 ///
80 /// Friction; `0` means off.
81 pub friction: f32,
82 /// Schwingung. `None` heißt aus.
83 ///
84 /// Oscillation. `None` means off.
85 pub vibration: Option<AxisVibration>,
86}
87
88/// Begrenzt einen endlichen Wert auf `0..=1`. Nicht endliche Werte werden 0.
89///
90/// Clamps a finite value to `0..=1`. Non-finite values become 0.
91pub fn clamp_unit(value: f32) -> f32 {
92 if value.is_finite() {
93 value.clamp(0.0, 1.0)
94 } else {
95 0.0
96 }
97}
98
99/// Begrenzt eine Frequenz auf `>= 0`. Nicht endliche Werte werden 0.
100///
101/// Clamps a frequency to `>= 0`. Non-finite values become 0.
102pub fn clamp_frequency_hz(value: f32) -> f32 {
103 if value.is_finite() {
104 value.max(0.0)
105 } else {
106 0.0
107 }
108}