1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
use crate::{Vec3, AABB};

/// A physical body in the Voxelize world.
#[derive(Default, Clone)]
pub struct RigidBody {
    /// If `body.collision` is true that tick, means there's a collision detected.
    pub collision: Option<[f32; 3]>,

    /// If the body stepped upwards that tick.
    pub stepped: bool,

    /// The amount of drag this body has in air.
    pub air_drag: f32,
    /// The amount of drag this body has in fluid.
    pub fluid_drag: f32,

    /// A vector representing which axis is the body resting against something.
    pub resting: Vec3<i32>,

    /// Whether or not this body is in fluid.
    pub in_fluid: bool,

    /// Ratio of body this body is in fluid.
    pub ratio_in_fluid: f32,

    /// Velocity vector of the rigid body.
    pub velocity: Vec3<f32>,

    /// Forces vector of the rigid body.
    pub forces: Vec3<f32>,

    /// Impulses vector of the rigid body.
    pub impulses: Vec3<f32>,

    /// Counts how many frames this rigid body is static.
    pub sleep_frame_count: i32,

    /// AABB of this rigid body, describing its collision box.
    pub aabb: AABB,

    /// Mass of this rigid body.
    pub mass: f32,

    /// Friction of this rigid body.
    pub friction: f32,

    /// Restitution of this rigid body.
    pub restitution: f32,

    /// Gravity Multiplier of this rigid body. Set to 0 to fly.
    pub gravity_multiplier: f32,

    /// Whether or not this rigid body auto-steps up blocks.
    pub auto_step: bool,
}

impl RigidBody {
    /// Instantiate a new RigidBody using the Builder's pattern.
    pub fn new(aabb: &AABB) -> RigidBodyBuilder {
        RigidBodyBuilder::new(aabb)
    }

    /// Setter for rigid body's position, which is the center of the rigid body.
    pub fn set_position(&mut self, px: f32, py: f32, pz: f32) {
        let [offset_w, offset_h, offset_d] = self.aabb_offset();

        self.aabb
            .set_position(px - offset_w, py - offset_h, pz - offset_d);
        self.mark_active()
    }

    /// Get the position of the rigid body, which is the bottom center of the rigid body.
    pub fn get_position(&self) -> Vec3<f32> {
        let [offset_w, offset_h, offset_d] = self.aabb_offset();
        Vec3(
            self.aabb.min_x + offset_w,
            self.aabb.min_y + offset_h,
            self.aabb.min_z + offset_d,
        )
    }

    /// Adds a vector to rigid body's internal force, which gets processed every tick.
    pub fn apply_force(&mut self, fx: f32, fy: f32, fz: f32) {
        self.forces[0] += fx;
        self.forces[1] += fy;
        self.forces[2] += fz;
        self.mark_active();
    }

    /// Adds a vector to rigid body's internal impulse, which gets processed every tick.
    pub fn apply_impulse(&mut self, ix: f32, iy: f32, iz: f32) {
        self.impulses[0] += ix;
        self.impulses[1] += iy;
        self.impulses[2] += iz;
        self.mark_active();
    }

    /// Get x-axis of the resting vector of a rigid body. A resting
    /// vector indicates whether a body is resting or not.
    pub fn at_rest_x(&self) -> i32 {
        self.resting[0]
    }

    /// Get y-axis of the resting vector of a rigid body. A resting
    /// vector indicates whether a body is resting or not.
    pub fn at_rest_y(&self) -> i32 {
        self.resting[1]
    }

    /// Get z-axis of the resting vector of a rigid body. A resting
    /// vector indicates whether a body is resting or not.
    pub fn at_rest_z(&self) -> i32 {
        self.resting[2]
    }

    /// Mark rigid body as active in the physical world.
    pub fn mark_active(&mut self) {
        self.sleep_frame_count = 10;
    }

    /// Compute the offset from the minimum coordinates to the bottom center.
    fn aabb_offset(&self) -> [f32; 3] {
        [
            self.aabb.width() / 2.0,
            self.aabb.height() / 2.0,
            self.aabb.depth() / 2.0,
        ]
    }
}

/// Builder pattern for RigidBody.
#[derive(Default)]
pub struct RigidBodyBuilder {
    aabb: AABB,
    mass: f32,
    friction: f32,
    restitution: f32,
    gravity_multiplier: f32,
    auto_step: bool,
}

impl RigidBodyBuilder {
    /// Create a new RigidBody with the builder pattern.
    pub fn new(aabb: &AABB) -> Self {
        Self {
            aabb: aabb.to_owned(),

            mass: 1.0,
            friction: 1.0,
            gravity_multiplier: 1.0,
            auto_step: false,

            ..Default::default()
        }
    }

    /// Configure the mass of this rigid body. Default is 1.0.
    pub fn mass(mut self, mass: f32) -> Self {
        self.mass = mass;
        self
    }

    /// Configure the friction of this rigid body. Default is 1.0.
    pub fn friction(mut self, friction: f32) -> Self {
        self.friction = friction;
        self
    }

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

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

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

    pub fn build(self) -> RigidBody {
        RigidBody {
            collision: None,
            stepped: false,

            air_drag: -1.0,
            fluid_drag: -1.0,

            resting: Vec3::default(),
            velocity: Vec3::default(),
            in_fluid: false,
            ratio_in_fluid: 0.0,
            forces: Vec3::default(),
            impulses: Vec3::default(),
            sleep_frame_count: 10 | 0,

            aabb: self.aabb,
            mass: self.mass,
            friction: self.friction,
            restitution: self.restitution,
            gravity_multiplier: self.gravity_multiplier,
            auto_step: self.auto_step,
        }
    }
}