c2/
lib.rs

1//! # Getting started
2//!
3//! ```rust
4//! use c2::{prelude::*, AABB, Circle, Capsule, Poly, Transformation, Rotation};
5//! use std::f32::consts::PI;
6//!
7//! fn main() {
8//!     let circle = Circle::new([0.0, 0.0], 15.0);
9//!     let aabb = AABB::new([10.0, 5.0], [20.0, 30.0]);
10//!
11//!     let collided = circle.collides_with(&aabb);
12//!     assert!(collided);
13//!
14//!     let capsule = Capsule::new([5.0, 5.0], [15.0, 10.0], 1.0);
15//!
16//!     let poly = Poly::from_slice(&[
17//!         [-1.0, -3.0],
18//!         [1.0, -3.0],
19//!         [1.0, 0.0],
20//!         [0.0, 1.0],
21//!         [-1.0, 0.0],
22//!     ]);
23//!
24//!     let collided = capsule.collides_with(&poly);
25//!     assert!(!collided);
26//!
27//!     let transformation =
28//!         Transformation::new([5.0, 4.0], Rotation::radians(PI / 2.0));
29//!
30//!     let collided = circle.collides_with(&(poly, transformation));
31//!     assert!(collided);
32//!     let manifold = circle.manifold(&poly);
33//!     /*
34//!         The manifold is used for resolving collisions and has the following methods:
35//!         manifold.count() -> i32
36//!         manifold.depths() -> [f32; 2]
37//!         manifold.contact_points() -> [Vec2; 2]
38//!         manifold.normal() -> Vec2
39//!     */
40//!
41//!     let gjk_response = poly.gjk(&circle).run();
42//!     /*
43//!         The result of the GJK algorithm:
44//!         gjk_response.distance() -> f32
45//!         gjk_response.closest_points() -> (Vec2, Vec2)
46//!     */
47//! }
48//! ```
49//!
50//! Check out [the library](https://github.com/RandyGaul/cute_headers/blob/master/cute_c2.h) this builds on top of for additional documentation.
51//! Please note the section entitled NUMERIC ROBUSTNESS.
52
53use c2_sys as ffi;
54use std::os::raw::c_void;
55
56const MAX_POLYGON_VERTS: usize = ffi::C2_MAX_POLYGON_VERTS as usize;
57
58/// A 2d vector
59#[derive(Debug, Copy, Clone)]
60pub struct Vec2(ffi::c2v);
61
62impl Vec2 {
63    /// Creates a new vector
64    pub fn new(x: f32, y: f32) -> Vec2 {
65        Vec2(ffi::c2v { x, y })
66    }
67
68    /// The x coordinate
69    pub fn x(self) -> f32 {
70        self.0.x
71    }
72
73    /// Set the x coordinate
74    pub fn set_x(&mut self, x: f32) {
75        self.0.x = x;
76    }
77
78    /// The y coordinate
79    pub fn y(self) -> f32 {
80        self.0.y
81    }
82
83    /// Set the y coordinate
84    pub fn set_y(&mut self, y: f32) {
85        self.0.y = y;
86    }
87}
88
89impl From<[f32; 2]> for Vec2 {
90    fn from(v: [f32; 2]) -> Vec2 {
91        Vec2::new(v[0], v[1])
92    }
93}
94
95/// Rotation, an angle
96#[derive(Debug, Copy, Clone)]
97pub struct Rotation(ffi::c2r);
98
99impl Rotation {
100    /// No rotation
101    pub fn zero() -> Self {
102        Rotation::radians(0.0)
103    }
104
105    // Rotation in radians
106    pub fn radians(radians: f32) -> Rotation {
107        Rotation(ffi::c2r {
108            c: radians.cos(),
109            s: radians.sin(),
110        })
111    }
112
113    /// Rotation in degrees
114    pub fn degrees(degrees: f32) -> Rotation {
115        Rotation::radians(degrees.to_radians())
116    }
117
118    /// cos(angle)
119    pub fn cos(self) -> f32 {
120        self.0.c
121    }
122
123    /// sin(angle)
124    pub fn sin(self) -> f32 {
125        self.0.s
126    }
127}
128
129/// A circle with a point and a radius
130#[derive(Debug, Copy, Clone)]
131pub struct Circle(ffi::c2Circle);
132
133impl Circle {
134    /// Creates a circle from a position and a radius
135    pub fn new<V: Into<Vec2>>(position: V, radius: f32) -> Circle {
136        Circle(ffi::c2Circle {
137            p: position.into().0,
138            r: radius,
139        })
140    }
141}
142
143/// Rectangle with a min vector and a max vector
144#[derive(Debug, Copy, Clone)]
145pub struct AABB(ffi::c2AABB);
146
147impl AABB {
148    /// Creates a new AABB rectangle
149    pub fn new<V: Into<Vec2>>(min: V, max: V) -> AABB {
150        AABB(ffi::c2AABB {
151            min: min.into().0,
152            max: max.into().0,
153        })
154    }
155
156    /// The minimum position
157    pub fn min(self) -> Vec2 {
158        Vec2(self.0.min)
159    }
160
161    /// The maximum position
162    pub fn max(self) -> Vec2 {
163        Vec2(self.0.max)
164    }
165}
166
167/// A capsule with a line segment and a radius
168#[derive(Debug, Copy, Clone)]
169pub struct Capsule(ffi::c2Capsule);
170
171impl Capsule {
172    /// Creates a capsule from a start position, an end position and a radius
173    pub fn new<V: Into<Vec2>>(start: V, end: V, radius: f32) -> Capsule {
174        Capsule(ffi::c2Capsule {
175            a: start.into().0,
176            b: end.into().0,
177            r: radius,
178        })
179    }
180}
181
182/// A polygon with up to 8 sides
183#[derive(Debug, Copy, Clone)]
184pub struct Poly(ffi::c2Poly);
185
186impl Poly {
187    /// Creates a polygon from a slice of vectors
188    pub fn from_slice<V: Copy + Into<Vec2>>(verts: &[V]) -> Poly {
189        let mut poly = ffi::c2Poly {
190            count: verts.len() as i32,
191            verts: [ffi::c2v { x: 0.0, y: 0.0 }; MAX_POLYGON_VERTS],
192            norms: [ffi::c2v { x: 0.0, y: 0.0 }; MAX_POLYGON_VERTS],
193        };
194        for i in 0..verts.len().min(MAX_POLYGON_VERTS) {
195            poly.verts[i] = verts[i].into().0;
196        }
197        unsafe {
198            ffi::c2MakePoly(&mut poly);
199        }
200        Poly(poly)
201    }
202
203    /// Creates a polygon from an array
204    pub fn from_array<V: Copy + Into<Vec2>>(count: usize, verts: [V; MAX_POLYGON_VERTS]) -> Poly {
205        Poly::from_slice(&verts[..count])
206    }
207
208    /// The number of sides
209    pub fn count(self) -> usize {
210        self.0.count as usize
211    }
212
213    /// Gets the point of the polygon at the index
214    pub fn get_vert(self, index: usize) -> Vec2 {
215        Vec2(self.0.verts[index])
216    }
217}
218
219/// For transforming the position and rotation of polygons
220#[derive(Debug, Copy, Clone)]
221pub struct Transformation(ffi::c2x);
222
223impl Transformation {
224    /// Creates a new transformation with a position and an angle
225    pub fn new<V: Into<Vec2>>(position: V, rotation: Rotation) -> Transformation {
226        Transformation(ffi::c2x {
227            p: position.into().0,
228            r: rotation.0,
229        })
230    }
231
232    /// Gets the position of the tranformation
233    pub fn position(self) -> Vec2 {
234        Vec2(self.0.p)
235    }
236
237    pub fn set_position(&mut self, position: Vec2) {
238        self.0.p = position.0;
239    }
240
241    /// Gets the rotation of the transformation
242    pub fn rotation(self) -> Rotation {
243        Rotation(self.0.r)
244    }
245
246    pub fn set_rotation(&mut self, rotation: Rotation) {
247        self.0.r = rotation.0;
248    }
249}
250
251/// A Ray struct for casting a ray
252pub struct Ray(ffi::c2Ray);
253
254impl Ray {
255    /// Creates a Ray with a position and a ray (a vector containing the direction and magnitude)
256    pub fn new<V: Into<Vec2>>(position: V, ray: V) -> Ray {
257        let ray = ray.into().0;
258        let distance = (ray.x * ray.x + ray.y * ray.y).sqrt();
259        let direction = Vec2::new(ray.x / distance, ray.y / distance);
260        Ray(ffi::c2Ray {
261            p: position.into().0,
262            d: direction.0,
263            t: distance,
264        })
265    }
266}
267
268/// The result of the ray casting operations
269#[derive(Debug, Copy, Clone)]
270pub struct RayCast(ffi::c2Raycast);
271
272impl RayCast {
273    pub fn time_of_impact(self) -> f32 {
274        self.0.t
275    }
276
277    pub fn position_of_impact(self, ray: Ray) -> Vec2 {
278        Vec2::new(
279            ray.0.p.x + ray.0.d.x * self.0.t,
280            ray.0.p.y + ray.0.d.y * self.0.t,
281        )
282    }
283
284    /// The normal of the surface at impact (unit length)
285    pub fn normal(self) -> Vec2 {
286        Vec2(self.0.n)
287    }
288}
289
290pub type GjkCache = ffi::c2GJKCache;
291
292/// Contains the data necessary for collision resolution
293#[derive(Debug, Copy, Clone)]
294pub struct Manifold(ffi::c2Manifold);
295
296impl Manifold {
297    pub fn count(self) -> i32 {
298        self.0.count
299    }
300
301    pub fn depths(self) -> [f32; 2] {
302        self.0.depths
303    }
304
305    pub fn contact_points(self) -> [Vec2; 2] {
306        [
307            Vec2(self.0.contact_points[0]),
308            Vec2(self.0.contact_points[1]),
309        ]
310    }
311
312    /// Points from the first shape to the second
313    pub fn normal(self) -> Vec2 {
314        Vec2(self.0.n)
315    }
316}
317
318/// The type of the shape
319#[repr(u32)]
320#[derive(Debug, Copy, Clone)]
321pub enum Type {
322    None = ffi::C2_TYPE_C2_TYPE_NONE,
323    Circle = ffi::C2_TYPE_C2_TYPE_CIRCLE,
324    AABB = ffi::C2_TYPE_C2_TYPE_AABB,
325    Capsule = ffi::C2_TYPE_C2_TYPE_CAPSULE,
326    Poly = ffi::C2_TYPE_C2_TYPE_POLY,
327}
328
329/// The result of the GJK function
330#[derive(Debug, Copy, Clone)]
331pub struct GjkResponse {
332    distance: f32,
333    closest_points: (Vec2, Vec2),
334}
335
336impl GjkResponse {
337    pub fn distance(self) -> f32 {
338        self.distance
339    }
340
341    pub fn closest_points(self) -> (Vec2, Vec2) {
342        self.closest_points
343    }
344}
345
346/// A builder for running the GJK algorithm
347pub struct GjkRunner<'a, ShapeA, ShapeB> {
348    a: &'a ShapeA,
349    b: &'a ShapeB,
350    use_radius: bool,
351    cache: Option<&'a mut GjkCache>,
352    iterations: Option<&'a mut i32>,
353}
354
355/// A builder for finding the time of impact for two shapes
356pub struct ToiRunner<'a, ShapeA, ShapeB> {
357    a: &'a ShapeA,
358    b: &'a ShapeB,
359    a_velocity: Vec2,
360    b_velocity: Vec2,
361    use_radius: bool,
362    iterations: Option<&'a mut i32>,
363}
364
365pub mod prelude {
366    use super::*;
367
368    impl Ray {
369        pub fn cast<T: Shape + AdvancedShape>(self, shape: T) -> Option<RayCast> {
370            unsafe {
371                let mut raycast = RayCast(ffi::c2Raycast {
372                    t: 0.0,
373                    n: Vec2::new(0.0, 0.0).0,
374                });
375                let hit = ffi::c2CastRay(
376                    self.0,
377                    shape.shape(),
378                    shape.transformation(),
379                    T::shape_type() as u32,
380                    &mut raycast.0,
381                );
382                if hit != 0 {
383                    Some(raycast)
384                } else {
385                    None
386                }
387            }
388        }
389    }
390
391    pub trait Shape {
392        fn shape_type() -> Type;
393
394        fn shape(&self) -> *const c_void {
395            self as *const _ as *const c_void
396        }
397
398        fn transformation(&self) -> *const ffi::c2x {
399            std::ptr::null()
400        }
401    }
402
403    pub trait BasicShape: Shape {
404        /// Returns true if the two shapes are colliding, false otherwise
405        fn collides_with<T: Shape>(&self, other: &T) -> bool {
406            unsafe {
407                ffi::c2Collided(
408                    self.shape(),
409                    self.transformation(),
410                    Self::shape_type() as u32,
411                    other.shape(),
412                    other.transformation(),
413                    T::shape_type() as u32,
414                ) != 0
415            }
416        }
417
418        /// Returns the Manifold struct for collision resolution
419        fn manifold<T: Shape>(&self, other: &T) -> Manifold {
420            let mut manifold = Manifold(ffi::c2Manifold {
421                count: 0,
422                depths: [0.0, 0.0],
423                contact_points: [ffi::c2v { x: 0.0, y: 0.0 }, ffi::c2v { x: 0.0, y: 0.0 }],
424                n: ffi::c2v { x: 0.0, y: 0.0 },
425            });
426            unsafe {
427                ffi::c2Collide(
428                    self.shape(),
429                    self.transformation(),
430                    Self::shape_type() as u32,
431                    other.shape(),
432                    other.transformation(),
433                    T::shape_type() as u32,
434                    &mut manifold.0,
435                );
436            }
437            manifold
438        }
439    }
440
441    impl<'a, ShapeA, ShapeB> GjkRunner<'a, ShapeA, ShapeB>
442    where
443        ShapeA: Shape,
444        ShapeB: Shape,
445    {
446        pub fn new(a: &'a ShapeA, b: &'a ShapeB) -> GjkRunner<'a, ShapeA, ShapeB> {
447            GjkRunner {
448                a,
449                b,
450                use_radius: true,
451                cache: None,
452                iterations: None,
453            }
454        }
455
456        pub fn use_radius(mut self, use_radius: bool) -> GjkRunner<'a, ShapeA, ShapeB> {
457            self.use_radius = use_radius;
458            self
459        }
460
461        pub fn set_cache(mut self, cache: &'a mut GjkCache) -> GjkRunner<'a, ShapeA, ShapeB> {
462            self.cache = Some(cache);
463            self
464        }
465
466        pub fn set_iterations(mut self, iterations: &'a mut i32) -> GjkRunner<'a, ShapeA, ShapeB> {
467            self.iterations = Some(iterations);
468            self
469        }
470
471        /// Finds the closest pair between two shapes
472        pub fn run(self) -> GjkResponse {
473            let mut response = GjkResponse {
474                distance: 0.0,
475                closest_points: (Vec2::new(0.0, 0.0), Vec2::new(0.0, 0.0)),
476            };
477            let cache_ptr = match self.cache {
478                Some(cache) => cache as *mut GjkCache,
479                None => std::ptr::null_mut(),
480            };
481            let iterations_ptr = match self.iterations {
482                Some(iterations) => iterations as *mut i32,
483                None => std::ptr::null_mut(),
484            };
485            unsafe {
486                let distance = ffi::c2GJK(
487                    self.a.shape(),
488                    ShapeA::shape_type() as u32,
489                    self.a.transformation(),
490                    self.b.shape(),
491                    ShapeB::shape_type() as u32,
492                    self.b.transformation(),
493                    &mut (response.closest_points.0).0,
494                    &mut (response.closest_points.1).0,
495                    self.use_radius as i32,
496                    iterations_ptr,
497                    cache_ptr,
498                );
499                response.distance = distance;
500            }
501            response
502        }
503    }
504
505    impl<'a, ShapeA, ShapeB> ToiRunner<'a, ShapeA, ShapeB>
506    where
507        ShapeA: Shape,
508        ShapeB: Shape,
509    {
510        pub fn new(a: &'a ShapeA, b: &'a ShapeB) -> ToiRunner<'a, ShapeA, ShapeB> {
511            ToiRunner {
512                a,
513                b,
514                a_velocity: Vec2::new(0.0, 0.0),
515                b_velocity: Vec2::new(0.0, 0.0),
516                use_radius: true,
517                iterations: None,
518            }
519        }
520
521        pub fn set_velocities(
522            mut self,
523            a_velocity: Vec2,
524            b_velocity: Vec2,
525        ) -> ToiRunner<'a, ShapeA, ShapeB> {
526            self.a_velocity = a_velocity;
527            self.b_velocity = b_velocity;
528            self
529        }
530
531        pub fn use_radius(mut self, use_radius: bool) -> ToiRunner<'a, ShapeA, ShapeB> {
532            self.use_radius = use_radius;
533            self
534        }
535
536        pub fn set_iterations(mut self, iterations: &'a mut i32) -> ToiRunner<'a, ShapeA, ShapeB> {
537            self.iterations = Some(iterations);
538            self
539        }
540
541        pub fn run(self) -> f32 {
542            let iterations_ptr = match self.iterations {
543                Some(iterations) => iterations as *mut i32,
544                None => std::ptr::null_mut(),
545            };
546            let result = unsafe {
547                ffi::c2TOI(
548                    self.a.shape(),
549                    ShapeA::shape_type() as u32,
550                    self.a.transformation(),
551                    self.a_velocity.0,
552                    self.b.shape(),
553                    ShapeB::shape_type() as u32,
554                    self.b.transformation(),
555                    self.b_velocity.0,
556                    self.use_radius as i32,
557                    iterations_ptr,
558                )
559            };
560            result
561        }
562    }
563
564    pub trait AdvancedShape: Shape {
565        fn gjk<'a, T: Shape>(&'a self, other: &'a T) -> GjkRunner<'a, Self, T>
566        where
567            Self: Sized,
568            T: Sized,
569        {
570            GjkRunner::new(self, other)
571        }
572
573        fn time_of_impact<'a, T: Shape>(&'a self, other: &'a T) -> ToiRunner<'a, Self, T>
574        where
575            Self: Sized,
576            T: Sized,
577        {
578            ToiRunner::new(self, other)
579        }
580    }
581
582    impl Shape for Circle {
583        fn shape_type() -> Type {
584            Type::Circle
585        }
586    }
587
588    impl BasicShape for Circle {}
589    impl AdvancedShape for Circle {}
590
591    impl Shape for AABB {
592        fn shape_type() -> Type {
593            Type::AABB
594        }
595    }
596
597    impl BasicShape for AABB {}
598    impl AdvancedShape for AABB {}
599
600    impl Shape for Capsule {
601        fn shape_type() -> Type {
602            Type::Capsule
603        }
604    }
605
606    impl BasicShape for Capsule {}
607    impl AdvancedShape for Capsule {}
608
609    impl Shape for Poly {
610        fn shape_type() -> Type {
611            Type::Poly
612        }
613    }
614
615    impl BasicShape for Poly {}
616    impl AdvancedShape for Poly {}
617
618    impl Shape for (Circle, Transformation) {
619        fn shape_type() -> Type {
620            Type::Circle
621        }
622
623        fn shape(&self) -> *const c_void {
624            &self.0 as *const _ as *const c_void
625        }
626
627        fn transformation(&self) -> *const ffi::c2x {
628            &self.1 as *const _ as *const ffi::c2x
629        }
630    }
631
632    impl AdvancedShape for (Circle, Transformation) {}
633
634    impl Shape for (AABB, Transformation) {
635        fn shape_type() -> Type {
636            Type::AABB
637        }
638
639        fn shape(&self) -> *const c_void {
640            &self.0 as *const _ as *const c_void
641        }
642
643        fn transformation(&self) -> *const ffi::c2x {
644            &self.1 as *const _ as *const ffi::c2x
645        }
646    }
647
648    impl AdvancedShape for (AABB, Transformation) {}
649
650    impl Shape for (Capsule, Transformation) {
651        fn shape_type() -> Type {
652            Type::Capsule
653        }
654
655        fn shape(&self) -> *const c_void {
656            &self.0 as *const _ as *const c_void
657        }
658
659        fn transformation(&self) -> *const ffi::c2x {
660            &self.1 as *const _ as *const ffi::c2x
661        }
662    }
663
664    impl AdvancedShape for (Capsule, Transformation) {}
665
666    impl Shape for (Poly, Transformation) {
667        fn shape_type() -> Type {
668            Type::Poly
669        }
670
671        fn shape(&self) -> *const c_void {
672            &self.0 as *const _ as *const c_void
673        }
674
675        fn transformation(&self) -> *const ffi::c2x {
676            &self.1 as *const _ as *const ffi::c2x
677        }
678    }
679
680    impl BasicShape for (Poly, Transformation) {}
681    impl AdvancedShape for (Poly, Transformation) {}
682}