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
use std::mem;
use std::ptr;
use std::slice;

use wrap::*;
use common::math::Vec2;
use super::{Shape, EdgeShape};

wrap_shape! {
    ffi::ChainShape => ChainShape
    < ffi::ChainShape_as_shape
    > ffi::Shape_as_chain_shape
}

impl ChainShape {
    pub fn new() -> Self {
        unsafe { ChainShape::from_ffi(ffi::ChainShape_new()) }
    }

    pub fn new_loop(vertices: &[Vec2]) -> Self {
        let mut s = Self::new();
        s.create_loop(vertices);
        s
    }

    pub fn new_chain(vertices: &[Vec2]) -> Self {
        let mut s = Self::new();
        s.create_chain(vertices);
        s
    }

    pub fn clear(&mut self) {
        unsafe { ffi::ChainShape_clear(self.mut_ptr()) }
    }

    pub fn create_loop(&mut self, vertices: &[Vec2]) {
        unsafe {
            ffi::ChainShape_create_loop(self.mut_ptr(), vertices.as_ptr(), vertices.len() as i32)
        }
    }

    pub fn create_chain(&mut self, vertices: &[Vec2]) {
        unsafe {
            ffi::ChainShape_create_chain(self.mut_ptr(), vertices.as_ptr(), vertices.len() as i32)
        }
    }

    pub fn vertices(&self) -> &[Vec2] {
        unsafe {
            let vertices = ffi::ChainShape_get_vertices_const(self.ptr());
            let count = ffi::ChainShape_get_vertex_count(self.ptr());
            slice::from_raw_parts(vertices, count as usize)
        }
    }

    pub fn prev_vertex(&self) -> Option<Vec2> {
        unsafe {
            let mut v = mem::MaybeUninit::uninit();
            if ffi::ChainShape_get_prev_vertex(self.ptr(), &mut *v.as_mut_ptr()) {
                Some(v.assume_init())
            } else {
                None
            }
        }
    }

    pub fn set_prev_vertex(&mut self, v: Option<Vec2>) {
        let ptr = v.as_ref().map(|v0| v0 as *const _).unwrap_or(ptr::null());
        unsafe { ffi::ChainShape_set_prev_vertex(self.mut_ptr(), ptr) }
    }

    pub fn next_vertex(&self) -> Option<Vec2> {
        unsafe {
            let mut v = mem::MaybeUninit::uninit();
            if ffi::ChainShape_get_next_vertex(self.ptr(), &mut *v.as_mut_ptr()) {
                Some(v.assume_init())
            } else {
                None
            }
        }
    }

    pub fn set_next_vertex(&mut self, v: Option<Vec2>) {
        let ptr = v.as_ref().map(|v0| v0 as *const _).unwrap_or(ptr::null());
        unsafe { ffi::ChainShape_set_next_vertex(self.mut_ptr(), ptr) }
    }

    pub fn child_edge(&self, index: i32) -> EdgeShape {
        unsafe {
            let mut edge = EdgeShape::new();
            ffi::ChainShape_get_child_edge(self.ptr(), edge.mut_ptr(), index);
            edge
        }
    }
}

impl Drop for ChainShape {
    fn drop(&mut self) {
        unsafe { ffi::ChainShape_drop(self.mut_ptr()) }
    }
}

#[doc(hidden)]
pub mod ffi {
    pub use collision::shapes::ffi::Shape;
    pub use collision::shapes::edge::ffi::EdgeShape;
    use common::math::Vec2;

    pub enum ChainShape {}

    extern "C" {
        pub fn ChainShape_new() -> *mut ChainShape;
        pub fn ChainShape_drop(slf: *mut ChainShape);
        pub fn ChainShape_as_shape(slf: *mut ChainShape) -> *mut Shape;
        pub fn Shape_as_chain_shape(slf: *mut Shape) -> *mut ChainShape;
        pub fn ChainShape_clear(slf: *mut ChainShape);
        pub fn ChainShape_create_loop(slf: *mut ChainShape, vertices: *const Vec2, count: i32);
        pub fn ChainShape_create_chain(slf: *mut ChainShape, vertices: *const Vec2, count: i32);
        pub fn ChainShape_get_vertices_const(slf: *const ChainShape) -> *const Vec2;
        pub fn ChainShape_get_vertex_count(slf: *const ChainShape) -> i32;
        pub fn ChainShape_get_prev_vertex(slf: *const ChainShape, prev: &mut Vec2) -> bool;
        pub fn ChainShape_set_prev_vertex(slf: *mut ChainShape, vertex: *const Vec2);
        pub fn ChainShape_get_next_vertex(slf: *const ChainShape, next: &mut Vec2) -> bool;
        pub fn ChainShape_set_next_vertex(slf: *mut ChainShape, vertex: *const Vec2);
        pub fn ChainShape_get_child_edge(slf: *const ChainShape,
                                         edge: *mut EdgeShape,
                                         index: i32);
    }
}