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
use wrap::*;
use common::math::Vec2;
use user_data::UserDataTypes;
use dynamics::world::{World, BodyHandle};
use dynamics::joints::{Joint, JointType, JointDef};

pub struct MotorJointDef {
    pub body_a: BodyHandle,
    pub body_b: BodyHandle,
    pub collide_connected: bool,
    pub linear_offset: Vec2,
    pub angular_offset: f32,
    pub max_force: f32,
    pub max_torque: f32,
    pub correction_factor: f32,
}

impl MotorJointDef {
    pub fn new(body_a: BodyHandle, body_b: BodyHandle) -> MotorJointDef {
        MotorJointDef {
            body_a: body_a,
            body_b: body_b,
            collide_connected: false,
            linear_offset: Vec2 { x: 0., y: 0. },
            angular_offset: 0.,
            max_force: 1.,
            max_torque: 1.,
            correction_factor: 0.3,
        }
    }

    pub fn init<U: UserDataTypes>(&mut self,
                                  world: &World<U>,
                                  body_a: BodyHandle,
                                  body_b: BodyHandle) {
        self.try_init(world, body_a, body_b).expect("joint init filed: invalid body handle");
    }

    pub fn try_init<U: UserDataTypes>(&mut self,
                                      world: &World<U>,
                                      body_a: BodyHandle,
                                      body_b: BodyHandle) -> Option<()> {
        self.body_a = body_a;
        self.body_b = body_b;
        let a = world.try_body(body_a)?;
        let b = world.try_body(body_b)?;
        self.linear_offset = a.local_point(b.position());
        self.angular_offset = b.angle() - a.angle();
        Some(())
    }
}

impl JointDef for MotorJointDef {
    fn joint_type() -> JointType
        where Self: Sized
    {
        JointType::Motor
    }

    unsafe fn create<U: UserDataTypes>(&self, world: &mut World<U>) -> *mut ffi::Joint {
        self.try_create(world).expect("joint create failed: invalid body handle")
    }

    unsafe fn try_create<U: UserDataTypes>(&self, world: &mut World<U>) -> Option<*mut ffi::Joint> {
        Some(ffi::World_create_motor_joint(world.mut_ptr(),
                                           world.try_body_mut(self.body_a)?.mut_ptr(),
                                           world.try_body_mut(self.body_b)?.mut_ptr(),
                                           self.collide_connected,
                                           self.linear_offset,
                                           self.angular_offset,
                                           self.max_force,
                                           self.max_torque,
                                           self.correction_factor))
    }
}

wrap_joint! {
    ffi::MotorJoint => MotorJoint (JointType::Motor)
    < ffi::MotorJoint_as_joint
    > ffi::Joint_as_motor_joint
}

impl MotorJoint {
    pub fn linear_offset<'a>(&'a self) -> &'a Vec2 {
        unsafe {
            &*ffi::MotorJoint_get_linear_offset(self.ptr()) // Comes from a C++ &
        }
    }

    pub fn angular_offset(&self) -> f32 {
        unsafe { ffi::MotorJoint_get_angular_offset(self.ptr()) }
    }

    pub fn max_force(&self) -> f32 {
        unsafe { ffi::MotorJoint_get_max_force(self.ptr()) }
    }

    pub fn max_torque(&self) -> f32 {
        unsafe { ffi::MotorJoint_get_max_torque(self.ptr()) }
    }

    pub fn correction_factor(&self) -> f32 {
        unsafe { ffi::MotorJoint_get_correction_factor(self.ptr()) }
    }

    pub fn set_linear_offset(&mut self, offset: &Vec2) {
        unsafe { ffi::MotorJoint_set_linear_offset(self.mut_ptr(), offset) }
    }

    pub fn set_angular_offset(&mut self, offset: f32) {
        unsafe { ffi::MotorJoint_set_angular_offset(self.mut_ptr(), offset) }
    }

    pub fn set_max_force(&mut self, force: f32) {
        unsafe { ffi::MotorJoint_set_max_force(self.mut_ptr(), force) }
    }

    pub fn set_max_torque(&mut self, torque: f32) {
        unsafe { ffi::MotorJoint_set_max_torque(self.mut_ptr(), torque) }
    }

    pub fn set_correction_factor(&mut self, factor: f32) {
        unsafe { ffi::MotorJoint_set_correction_factor(self.mut_ptr(), factor) }
    }
}

#[doc(hidden)]
pub mod ffi {
    pub use dynamics::world::ffi::World;
    pub use dynamics::body::ffi::Body;
    pub use dynamics::joints::ffi::Joint;
    use common::math::Vec2;

    pub enum MotorJoint {}

    extern "C" {
        pub fn World_create_motor_joint(world: *mut World,
                                        body_a: *mut Body,
                                        body_b: *mut Body,
                                        collide_connected: bool,
                                        linear_offset: Vec2,
                                        angular_offset: f32,
                                        max_force: f32,
                                        max_torque: f32,
                                        correction_factor: f32)
                                        -> *mut Joint;
        pub fn MotorJoint_as_joint(slf: *mut MotorJoint) -> *mut Joint;
        pub fn Joint_as_motor_joint(slf: *mut Joint) -> *mut MotorJoint;
        pub fn MotorJoint_set_linear_offset(slf: *mut MotorJoint, offset: *const Vec2);
        pub fn MotorJoint_get_linear_offset(slf: *const MotorJoint) -> *const Vec2;
        pub fn MotorJoint_set_angular_offset(slf: *mut MotorJoint, offset: f32);
        pub fn MotorJoint_get_angular_offset(slf: *const MotorJoint) -> f32;
        pub fn MotorJoint_set_max_force(slf: *mut MotorJoint, force: f32);
        pub fn MotorJoint_get_max_force(slf: *const MotorJoint) -> f32;
        pub fn MotorJoint_set_max_torque(slf: *mut MotorJoint, torque: f32);
        pub fn MotorJoint_get_max_torque(slf: *const MotorJoint) -> f32;
        pub fn MotorJoint_set_correction_factor(slf: *mut MotorJoint, factor: f32);
        pub fn MotorJoint_get_correction_factor(slf: *const MotorJoint) -> f32;
    }
}