Pico Headers
Loading...
Searching...
No Matches
pico_hit.h
Go to the documentation of this file.
1
64#ifndef PICO_HIT_H
65#define PICO_HIT_H
66
67#include "pico_math.h"
68
69#ifdef __cplusplus
70extern "C" {
71#endif
72
73// Maximum number of vertices in a polygon
74#ifndef PICO_HIT_MAX_POLY_VERTS
75#define PICO_HIT_MAX_POLY_VERTS 16
76#endif
77
81typedef struct
82{
86
98
102typedef struct
103{
107} ph_ray_t;
108
120
124typedef struct
125{
129
136
143ph_poly_t ph_make_poly(const pv2 vertices[], int vertex_count);
144
152
159
167bool ph_sat_poly_poly(const ph_poly_t* poly_a,
168 const ph_poly_t* poly_b,
169 ph_manifold_t* manifold);
170
179 const ph_circle_t* circle,
180 ph_manifold_t* manifold);
181
190 const ph_poly_t* poly,
191 ph_manifold_t* manifold);
192
201 const ph_circle_t* circle_b,
202 ph_manifold_t* manifold);
203
213bool ph_ray_line(const ph_ray_t* ray, pv2 s1, pv2 s2, ph_raycast_t* raycast);
214
223bool ph_ray_poly(const ph_ray_t* ray, const ph_poly_t* poly, ph_raycast_t* raycast);
224
233bool ph_ray_circle(const ph_ray_t* ray, const ph_circle_t* circle, ph_raycast_t* raycast);
234
238pv2 ph_ray_at(const ph_ray_t* ray, pfloat dist);
239
246ph_poly_t ph_transform_poly(const pt2* transform, const ph_poly_t* poly);
247
254ph_circle_t ph_transform_circle(const pt2* transform, const ph_circle_t* circle);
255
260
265
266#ifdef __cplusplus
267}
268#endif
269
270#endif // PICO_HIT_H
271
272#ifdef PICO_HIT_IMPLEMENTATION // Define once
273
274#ifdef NDEBUG
275 #define PICO_HIT_ASSERT(expr) ((void)0)
276#else
277 #ifndef PICO_HIT_ASSERT
278 #include <assert.h>
279 #define PICO_HIT_ASSERT(expr) (assert(expr))
280 #endif
281#endif
282
283#define SAT_ASSERT PICO_HIT_ASSERT // Alias
284
285/*=============================================================================
286 * Internal function declarations
287 *============================================================================*/
288
289// Initializes a manifold
290static void ph_init_manifold(ph_manifold_t* manifold);
291
292// Updates manifold if requried
293static void ph_update_manifold(ph_manifold_t* manifold,
294 pv2 normal,
295 pfloat overlap);
296
297// Determines the polygon's limits when projected onto the normal vector
298static void ph_axis_range(const ph_poly_t* poly, pv2 normal, pfloat range[2]);
299
300// Determines the amount overlap of the polygons along the specified axis
301static pfloat ph_axis_overlap(const ph_poly_t* poly_a,
302 const ph_poly_t* poly_b,
303 pv2 axis);
304
305// Line Voronoi regions
306typedef enum
307{
308 PH_VORONOI_LEFT,
309 PH_VORONOI_RIGHT,
310 PH_VORONOI_MIDDLE
311} ph_voronoi_region_t;
312
313// Determines the Voronoi region the point belongs to along the specified line
314//
315// | (0) |
316// (-1) [L]--------------[R] (1)
317// | ^ (0) |
318// line
319static ph_voronoi_region_t ph_voronoi_region(pv2 point, pv2 line);
320
321// 2D matrix
322typedef struct
323{
324 pfloat a11, a12, a21, a22;
325} ph_m2;
326
327// Determinant of 2D matrix
328static pfloat ph_m2_det(ph_m2 m);
329
330// Inverse of 2D matrix
331static ph_m2 ph_m2_inverse(ph_m2 m, pfloat det);
332
333// Map 2D vector by 2D matrix
334static pv2 ph_m2_map(ph_m2 m, pv2 v);
335
336/*=============================================================================
337 * Public API implementation
338 *============================================================================*/
339
341{
342 ph_circle_t circle;
343 circle.pos = pos;
344 circle.radius = radius;
345 return circle;
346}
347
348ph_poly_t ph_make_poly(const pv2 vertices[], int vertex_count)
349{
350 SAT_ASSERT(vertex_count <= PICO_HIT_MAX_POLY_VERTS);
351 SAT_ASSERT(vertices);
352
353 ph_poly_t poly;
354
355 // Copy vertices
356 poly.vertex_count = vertex_count;
357
358 for (int i = 0; i < vertex_count; i++)
359 {
360 poly.vertices[i] = vertices[i];
361 }
362
363 // Cache edges and edge normals
364 for (int i = 0; i < vertex_count; i++)
365 {
366 int next = (i + 1) == vertex_count ? 0 : i + 1;
367
368 pv2 v1 = vertices[i];
369 pv2 v2 = vertices[next];
370 poly.edges[i] = pv2_sub(v2, v1);
371 poly.normals[i] = pv2_perp(poly.edges[i]);
372 poly.normals[i] = pv2_normalize(poly.normals[i]);
373 }
374
375 return poly;
376}
377
378ph_ray_t ph_make_ray(pv2 pos, pv2 dir, pfloat dist)
379{
380 return (ph_ray_t){ pos, pv2_normalize(dir), dist };
381}
382
383ph_poly_t ph_aabb_to_poly(const pb2* aabb)
384{
385 SAT_ASSERT(aabb);
386
387 // Get AABB properties
388 pv2 pos = pb2_get_pos(aabb);
389 pv2 size = pb2_get_size(aabb);
390
391 // Specify AABB vertices using CCW winding
392 pv2 vertices[] =
393 {
394 { pos.x, pos.y },
395 { pos.x, pos.y + size.y },
396 { pos.x + size.x, pos.y + size.y },
397 { pos.x + size.x, pos.y }
398 };
399
400 return ph_make_poly(vertices, 4);
401}
402
403bool ph_sat_poly_poly(const ph_poly_t* poly_a,
404 const ph_poly_t* poly_b,
405 ph_manifold_t* manifold)
406{
407 SAT_ASSERT(poly_a);
408 SAT_ASSERT(poly_b);
409
410 if (manifold)
411 ph_init_manifold(manifold);
412
413 // Test axises on poly_a
414 for (int i = 0; i < poly_a->vertex_count; i++)
415 {
416 // Get signed overlap of poly_a on poly_b along specified normal direction
417 pfloat overlap = ph_axis_overlap(poly_a, poly_b, poly_a->normals[i]);
418
419 // Axis is separating, polygons do not overlap
420 if (overlap == 0.0f)
421 return false;
422
423 // Update manifold information with new overlap and normal
424 if (manifold)
425 ph_update_manifold(manifold, poly_a->normals[i], overlap);
426 }
427
428 // Test axises on poly_b
429 for (int i = 0; i < poly_b->vertex_count; i++)
430 {
431 // Get signed overlap of poly_b on poly_a along specified normal direction
432 pfloat overlap = ph_axis_overlap(poly_b, poly_a, poly_b->normals[i]);
433
434 // Axis is separating, polygons do not overlap
435 if (overlap == 0.0f)
436 return false;
437
438 // Update manifold information with new overlap and normal
439 if (manifold)
440 ph_update_manifold(manifold, poly_b->normals[i], overlap);
441 }
442
443 return true;
444}
445
446bool ph_sat_poly_circle(const ph_poly_t* poly,
447 const ph_circle_t* circle,
448 ph_manifold_t* manifold)
449{
450 SAT_ASSERT(poly);
451 SAT_ASSERT(circle);
452
453 if (manifold)
454 ph_init_manifold(manifold);
455
456 pfloat radius2 = circle->radius * circle->radius;
457
458 // The main idea behind this function is to classify the position of the
459 // circle relative to the Voronoi region(s) it is part of. This uses very
460 // inexpensive operations. Essentially it efficiently narrows down the
461 // position of the circle so that the correct separating axis test can be
462 // performed.
463
464 int count = poly->vertex_count;
465
466 for (int i = 0; i < count; i++)
467 {
468 int next = (i + 1) == count ? 0 : i + 1;
469 int prev = (i - 1) <= 0 ? count - 1 : i - 1;
470
471 // Edge to test
472 pv2 edge = poly->edges[i];
473
474 // Postion of circle relative to vertex
475 pv2 point = pv2_sub(circle->pos, poly->vertices[i]);
476
477 // Find the Voronoi region of the point (circle center relative to
478 // vertex) with respect to the edge
479 ph_voronoi_region_t region = ph_voronoi_region(point, edge);
480
481 // Test if point is in the left Voronoi region
482 if (region == PH_VORONOI_LEFT)
483 {
484 // If it is, check if it is in the right Voronoi region of the
485 // previous edge. If this is the case, the circle is "sandwiched"
486 // in the intersection of the Voronoi regions defined by the
487 // endpoints of the edges.
488
489 pv2 point2 = pv2_sub(circle->pos, poly->vertices[prev]);
490 edge = poly->edges[prev];
491
492 region = ph_voronoi_region(point2, edge);
493
494 if (region == PH_VORONOI_RIGHT)
495 {
496 // The circle center is in the left/right Voronoi region, so
497 // check to see if it contains the vertex
498 pfloat diff2 = pv2_len2(point);
499
500 // Equivalent to diff > radius
501 if (diff2 > radius2)
502 return false;
503
504 // Vertex is contained within circle, so the circle overlaps the
505 // polygon
506
507 if (manifold)
508 {
509 // Calculate distance because we need it now
510 pfloat diff = pf_sqrt(diff2);
511
512 // Calculate overlap
513 pfloat overlap = circle->radius - diff;
514
515 // Normal direction is just the circle relative to the vertex
516 pv2 normal = pv2_normalize(point);
517
518 // Update manifold
519 ph_update_manifold(manifold, normal, overlap);
520 }
521 }
522 }
523 // This case is symmetric to the above
524 else if (region == PH_VORONOI_RIGHT)
525 {
526 pv2 point2 = pv2_sub(circle->pos, poly->vertices[next]);
527 edge = poly->edges[next];
528
529 region = ph_voronoi_region(point2, edge);
530
531 if (region == PH_VORONOI_LEFT)
532 {
533 pfloat diff2 = pv2_len2(point);
534
535 if (diff2 > radius2)
536 return false;
537
538 if (manifold)
539 {
540 pfloat diff = pf_sqrt(diff2);
541 pfloat overlap = circle->radius - diff;
542 pv2 normal = pv2_normalize(point);
543 ph_update_manifold(manifold, normal, overlap);
544 }
545 }
546 }
547 else // PH_VORONOI_MIDDLE
548 {
549 // In this case, the location of the circle is between the endpoints
550 // of an edge.
551 pv2 normal = poly->normals[i];
552
553 // Location of center of circle along the edge normal
554 pfloat diff = pv2_dot(normal, point);
555 pfloat abs_diff = pf_abs(diff);
556
557 // Test if circle does not intersect edge
558 if (diff > 0.0f && abs_diff > circle->radius)
559 return false;
560
561 if (manifold)
562 {
563 // Calculate overlap
564 pfloat overlap = circle->radius - diff;
565
566 // Update manifold
567 ph_update_manifold(manifold, normal, overlap);
568 }
569 }
570 }
571
572 return true;
573}
574
575bool ph_sat_circle_poly(const ph_circle_t* circle,
576 const ph_poly_t* poly,
577 ph_manifold_t* manifold)
578{
579 SAT_ASSERT(poly);
580 SAT_ASSERT(circle);
581
582 bool hit = ph_sat_poly_circle(poly, circle, (manifold) ? manifold : NULL);
583
584 if (hit && manifold)
585 {
586 // Since arguments were swapped, reversing these vectors is all that is
587 // required
588 manifold->normal = pv2_reflect(manifold->normal);
589 manifold->vector = pv2_reflect(manifold->vector);
590 }
591
592 return hit;
593}
594
595bool ph_sat_circle_circle(const ph_circle_t* circle_a,
596 const ph_circle_t* circle_b,
597 ph_manifold_t* manifold)
598{
599 SAT_ASSERT(circle_a);
600 SAT_ASSERT(circle_b);
601
602 if (manifold)
603 ph_init_manifold(manifold);
604
605 // Position of circle_b relative to circle_a
606 pv2 diff = pv2_sub(circle_b->pos, circle_a->pos);
607
608 // Squared distance between circle centers
609 pfloat dist2 = pv2_len2(diff);
610
611 // Sum of radii
612 pfloat total_radius = circle_a->radius + circle_b->radius;
613
614 // Square sum of radii for optimization (avoid calculating length until we
615 // have to)
616 pfloat total_radius2 = total_radius * total_radius;
617
618 // Equivalent to dist >= total_radius
619 if (dist2 >= total_radius2)
620 return false;
621
622 if (manifold)
623 {
624 // Calculate distance because we need it now
625 pfloat dist = pf_sqrt(dist2);
626
627 // Calculate overlap
628 pfloat overlap = total_radius - dist;
629
630 // Normal direction is just circle_b relative to circle_a
631 pv2 normal = pv2_normalize(diff);
632
633 // Update manifold
634 ph_update_manifold(manifold, normal, overlap);
635 }
636
637 return true;
638}
639
640/*
641 The basic idea here is to represent the rays in parametric form and
642 solve a linear equation to get the parameters where they intersect.
643 In this application we are only interested in the case where both of them
644 are contained in the interval [0, 1]
645*/
646bool ph_ray_line(const ph_ray_t* ray, pv2 s1, pv2 s2, ph_raycast_t* raycast)
647{
648 pv2 r1 = ray->pos;
649 pv2 r2 = pv2_add(ray->pos, pv2_scale(ray->dir, ray->dist));
650
651 pv2 v = pv2_sub(r2, r1);
652 pv2 w = pv2_sub(s2, s1);
653
654 ph_m2 m =
655 {
656 -v.x, w.x,
657 -v.y, w.y,
658 };
659
660 pfloat det = ph_m2_det(m);
661
662 if (pf_equal(det, 0.0f))
663 return false;
664
665 ph_m2 m_inv = ph_m2_inverse(m, det);
666
667 pv2 c = pv2_sub(r1, s1);
668 pv2 p = ph_m2_map(m_inv, c);
669
670 bool hit = 0.0f <= p.x && p.x <= 1.0f &&
671 0.0f <= p.y && p.y <= 1.0f;
672
673 if (hit && raycast)
674 {
675 raycast->normal = pv2_normalize(pv2_perp(w));
676 raycast->dist = p.x * ray->dist;
677 }
678
679 return hit;
680}
681
682/*
683 The idea behind this function is to use ph_ray_line on each of the edges
684 that make up the polygon. The function can exit early if the raycast is null.
685 Otherwise all edges of the polygon will be tested.
686*/
687bool ph_ray_poly(const ph_ray_t* ray, const ph_poly_t* poly, ph_raycast_t* raycast)
688{
689 pv2 min_normal = pv2_zero();
690 pfloat min_dist = PM_FLOAT_MAX;
691
692 bool has_hit = false;
693
694 for (int i = 0; i < poly->vertex_count; i++)
695 {
696 int next = (i + 1) == poly->vertex_count ? 0 : i + 1;
697
698 pv2 s1 = poly->vertices[i];
699 pv2 s2 = poly->vertices[next];
700
701 bool hit = ph_ray_line(ray, s1, s2, raycast);
702
703 if (hit && raycast)
704 {
705 has_hit = true;
706
707 if (raycast->dist < min_dist)
708 {
709 min_dist = raycast->dist;
710 min_normal = raycast->normal;
711 }
712 }
713 else if (hit)
714 {
715 return true;
716 }
717 }
718
719 if (has_hit)
720 {
721 raycast->dist = min_dist;
722 raycast->normal = min_normal;
723 return true;
724 }
725
726 return false;
727}
728
729/*
730 The idea behind this function is to represent a constraint, that determines
731 whether the ray intersects the circle, as a polynomial. The discriminant of
732 the quadratic fomula is used to test various cases corresponding to the
733 location and direction of the ray, and the circle.
734
735 Source: Real-Time Collision Detection by Christer Ericson
736*/
737bool ph_ray_circle(const ph_ray_t* ray, const ph_circle_t* circle, ph_raycast_t* raycast)
738{
739 pfloat r = circle->radius;
740 pv2 m = pv2_sub(ray->pos, circle->pos);
741 pfloat b = pv2_dot(m, ray->dir);
742 pfloat c = pv2_dot(m, m) - r * r;
743
744 if (c > 0.0f && b > 0.0f)
745 return false;
746
747 pfloat discr = b * b - c;
748
749 if (discr < 0.0f)
750 return false;
751
752 if (raycast)
753 {
754 pfloat dist = -b - pf_sqrt(discr);
755
756 if (dist < 0.0f)
757 dist = 0.0f;
758
759 pv2 p = pv2_add(ray->pos, pv2_scale(ray->dir, dist));
760
761 raycast->dist = dist;
762 raycast->normal = pv2_normalize(pv2_sub(p, circle->pos));
763 }
764
765 return true;
766}
767
768pv2 ph_ray_at(const ph_ray_t* ray, pfloat dist)
769{
770 return pv2_add(ray->pos, pv2_scale(ray->dir, dist));
771}
772
773ph_poly_t ph_transform_poly(const pt2* transform, const ph_poly_t* poly)
774{
775 pv2 vertices[poly->vertex_count];
776
777 for (int i = 0; i < poly->vertex_count; i++)
778 {
779 vertices[i] = pt2_map(transform, poly->vertices[i]);
780 }
781
782 return ph_make_poly(vertices, poly->vertex_count);
783}
784
785ph_circle_t ph_transform_circle(const pt2* transform,
786 const ph_circle_t* circle)
787{
788 return ph_make_circle(pt2_map(transform, circle->pos), circle->radius);
789}
790
791pb2 ph_poly_to_aabb(const ph_poly_t* poly)
792{
793 return pb2_enclosing(poly->vertices, poly->vertex_count);
794}
795
796pb2 ph_circle_to_aabb(const ph_circle_t* circle)
797{
798 pv2 half_radius = pv2_make(circle->radius / 2.0f, circle->radius / 2.0f);
799
800 pv2 min = pv2_sub(circle->pos, half_radius);
801 pv2 max = pv2_add(circle->pos, half_radius);
802
803 return pb2_make_minmax(min, max);
804}
805
806/*=============================================================================
807 * Internal function definitions
808 *============================================================================*/
809
810static void ph_init_manifold(ph_manifold_t* manifold)
811{
812 SAT_ASSERT(manifold);
813
814 manifold->overlap = PM_FLOAT_MAX;
815 manifold->normal = pv2_zero();
816 manifold->vector = pv2_zero();
817}
818
819static void ph_update_manifold(ph_manifold_t* manifold, pv2 normal, pfloat overlap)
820{
821 SAT_ASSERT(manifold);
822
823 pfloat abs_overlap = pf_abs(overlap);
824
825 // Only update if the new overlap is smaller than the old one
826 if (abs_overlap < manifold->overlap)
827 {
828 // Update overlap (always positive)
829 manifold->overlap = abs_overlap;
830
831 // If the overlap is less that zero the normal must be reversed
832 if (overlap < 0.0f)
833 manifold->normal = pv2_reflect(normal);
834 else if (overlap > 0.0f)
835 manifold->normal = normal;
836
837 manifold->vector = pv2_scale(manifold->normal, manifold->overlap);
838 }
839}
840
841static void ph_axis_range(const ph_poly_t* poly, pv2 normal, pfloat range[2])
842{
843 SAT_ASSERT(poly);
844 SAT_ASSERT(range);
845
846 pfloat dot = pv2_dot(poly->vertices[0], normal);
847 pfloat min = dot;
848 pfloat max = dot;
849
850 // Find the minimum and maximum distance of the polygon along the normal
851 for (int i = 1; i < poly->vertex_count; i++)
852 {
853 dot = pv2_dot(poly->vertices[i], normal);
854
855 if (dot < min)
856 min = dot;
857
858 if (dot > max)
859 max = dot;
860 }
861
862 // The range defines the interval induced by the polygon projected onto the
863 // normal vector
864 range[0] = min;
865 range[1] = max;
866}
867
868static pfloat ph_axis_overlap(const ph_poly_t* poly_a,
869 const ph_poly_t* poly_b,
870 pv2 axis)
871
872{
873 SAT_ASSERT(poly_a);
874 SAT_ASSERT(poly_b);
875
876 pfloat range_a[2];
877 pfloat range_b[2];
878
879 // Get the ranges of polygons projected onto the axis vector
880 ph_axis_range(poly_a, axis, range_a);
881 ph_axis_range(poly_b, axis, range_b);
882
883 // Ranges do not overlaps
884 if (range_a[1] < range_b[0] || range_b[1] < range_a[0])
885 return 0.0f;
886
887 // Calculate overlap candidates
888 pfloat overlap1 = range_a[1] - range_b[0];
889 pfloat overlap2 = range_b[1] - range_a[0];
890
891 // Return the smaller overlap
892 return (overlap2 > overlap1) ? overlap1 : -overlap2;
893}
894
895static ph_voronoi_region_t ph_voronoi_region(pv2 point, pv2 line)
896{
897 pfloat len2 = pv2_len2(line);
898 pfloat dot = pv2_dot(point, line);
899
900 if (dot < 0.0f) // Point is to the left of the line
901 return PH_VORONOI_LEFT;
902 else if (dot > len2) // Point is to the right of the line
903 return PH_VORONOI_RIGHT;
904 else
905 return PH_VORONOI_MIDDLE; // Point is somewhere in the middle
906}
907
908// Determinant of 2D matrix
909static pfloat ph_m2_det(ph_m2 m)
910{
911 return m.a11 * m.a22 - m.a21 * m.a12;
912}
913
914// Inverse of 2D matrix
915static ph_m2 ph_m2_inverse(ph_m2 m, pfloat det)
916{
917 pfloat inv_det = 1.0f / det;
918 return (ph_m2) { m.a22 * inv_det, -m.a12 * inv_det, -m.a21 * inv_det, m.a11 * inv_det };
919}
920
921// Map 2D vector by 2D matrix
922static pv2 ph_m2_map(ph_m2 m, pv2 v)
923{
924 return (pv2){ m.a11 * v.x + m.a12 * v.y, m.a21 * v.x + m.a22 * v.y };
925}
926
927#endif // PICO_HIT_IMPLEMENTATION
928
929/*
930The MIT License (MIT)
931
932Copyright (C) 2022 by James McLean
933Copyright (C) 2012 - 2015 by Jim Riecken
934
935Permission is hereby granted, free of charge, to any person obtaining a copy
936of this software and associated documentation files (the "Software"), to deal
937in the Software without restriction, including without limitation the rights
938to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
939copies of the Software, and to permit persons to whom the Software is
940furnished to do so, subject to the following conditions:
941
942The above copyright notice and this permission notice shall be included in
943all copies or substantial portions of the Software.
944
945THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
946IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
947FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
948AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
949LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
950OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
951THE SOFTWARE.
952*/
953
ph_poly_t ph_transform_poly(const pt2 *transform, const ph_poly_t *poly)
Transforms a polygon using an affine transform.
ph_ray_t ph_make_ray(pv2 pos, pv2 dir, pfloat dist)
Constructs a ray.
pb2 ph_poly_to_aabb(const ph_poly_t *poly)
Returns the bounding box for the given polygon.
ph_circle_t ph_transform_circle(const pt2 *transform, const ph_circle_t *circle)
Transforms a circle using an affine transform.
bool ph_sat_poly_poly(const ph_poly_t *poly_a, const ph_poly_t *poly_b, ph_manifold_t *manifold)
Tests to see if one polygon overlaps with another.
#define PICO_HIT_MAX_POLY_VERTS
Definition pico_hit.h:75
ph_poly_t ph_make_poly(const pv2 vertices[], int vertex_count)
Initializes a polygon.
bool ph_ray_circle(const ph_ray_t *ray, const ph_circle_t *circle, ph_raycast_t *raycast)
Tests if ray intersects a circle.
ph_poly_t ph_aabb_to_poly(const pb2 *aabb)
Converts and axis-aligned bounding box (AABB) to a polygon.
pb2 ph_circle_to_aabb(const ph_circle_t *circle)
Returns the bounding box for the given circle.
bool ph_ray_line(const ph_ray_t *ray, pv2 s1, pv2 s2, ph_raycast_t *raycast)
Tests if ray intersects a (directed) line segment.
bool ph_sat_circle_circle(const ph_circle_t *circle_a, const ph_circle_t *circle_b, ph_manifold_t *manifold)
Tests to see if two circles overlap.
bool ph_sat_poly_circle(const ph_poly_t *poly, const ph_circle_t *circle, ph_manifold_t *manifold)
Tests to see if a polygon overlaps a circle.
bool ph_sat_circle_poly(const ph_circle_t *circle, const ph_poly_t *poly, ph_manifold_t *manifold)
Tests to see if a circle overlaps a polygon.
ph_circle_t ph_make_circle(pv2 pos, pfloat radius)
Initializes a circle.
bool ph_ray_poly(const ph_ray_t *ray, const ph_poly_t *poly, ph_raycast_t *raycast)
Tests if ray intersects a polygon.
pv2 ph_ray_at(const ph_ray_t *ray, pfloat dist)
Finds the point along the ray at the specified distance from the origin.
A 2D math library for games.
PM_INLINE pfloat pv2_dot(pv2 v1, pv2 v2)
Dot product.
Definition pico_math.h:312
#define pv2_make(x, y)
Constructs a vector.
Definition pico_math.h:268
#define pv2_zero()
Returns the zero vector.
Definition pico_math.h:423
PM_INLINE pv2 pv2_scale(pv2 v, pfloat c)
Scales a vector.
Definition pico_math.h:304
PM_INLINE pv2 pv2_normalize(pv2 v)
Normalizes a vector (sets its length to one)
Definition pico_math.h:338
PM_INLINE pv2 pb2_get_pos(const pb2 *b)
Returns the position of an AABB.
Definition pico_math.h:666
PM_INLINE bool pf_equal(pfloat c1, pfloat c2)
Returns true if the values are within epsilon of one another.
Definition pico_math.h:221
PM_INLINE pv2 pv2_sub(pv2 v1, pv2 v2)
Subtracts two vectors.
Definition pico_math.h:294
float pfloat
A single precision floating point number.
Definition pico_math.h:137
#define PM_FLOAT_MAX
Definition pico_math.h:146
#define pb2_make_minmax(min, max)
Definition pico_math.h:651
#define pf_sqrt
Definition pico_math.h:148
#define pf_abs
Definition pico_math.h:154
PM_INLINE pfloat pv2_len2(pv2 v)
Returns the square of the length of the vector.
Definition pico_math.h:320
PM_INLINE pv2 pv2_perp(pv2 v)
Construct a vector that is perpendicular to the specified vector.
Definition pico_math.h:363
PM_INLINE pv2 pb2_get_size(const pb2 *b)
Returns the dimensions of an AABB.
Definition pico_math.h:674
PM_INLINE pv2 pv2_add(pv2 v1, pv2 v2)
Adds two vectors.
Definition pico_math.h:284
pb2 pb2_enclosing(const pv2 verts[], int count)
Computes the minimum box containing all of the vertices.
PM_INLINE pv2 pv2_reflect(pv2 v)
Negates a vector (scales it by -1.0)
Definition pico_math.h:353
PM_INLINE pv2 pt2_map(const pt2 *t, pv2 v)
Transforms a vector.
Definition pico_math.h:549
A 2D axis-aligned-bounding-box (AABB)
Definition pico_math.h:189
A circle shape.
Definition pico_hit.h:82
pfloat radius
Radius of the circle.
Definition pico_hit.h:84
pv2 pos
Center of circle.
Definition pico_hit.h:83
A collision manifold Provides information about a collision. Normals always point from shape 1 to sha...
Definition pico_hit.h:115
pfloat overlap
Amount of overlap between two shapes along colliding axis (MTD)
Definition pico_hit.h:117
pv2 vector
Vector defined by vector = normal * overlap
Definition pico_hit.h:118
pv2 normal
Normal to colliding edge (in direction of MTV)
Definition pico_hit.h:116
A polygon shape Must use CCW (counter-clockwise) winding.
Definition pico_hit.h:92
pv2 normals[PICO_HIT_MAX_POLY_VERTS]
Polygon edge normals.
Definition pico_hit.h:95
pv2 edges[PICO_HIT_MAX_POLY_VERTS]
Edges of polygon.
Definition pico_hit.h:96
int vertex_count
Number of vertices in polygon.
Definition pico_hit.h:93
pv2 vertices[PICO_HIT_MAX_POLY_VERTS]
Polygon vertices.
Definition pico_hit.h:94
A ray (directed line segment)
Definition pico_hit.h:103
pv2 pos
The origin of the ray.
Definition pico_hit.h:104
pv2 dir
The direction of the ray (normalized)
Definition pico_hit.h:105
pfloat dist
The length of the ray.
Definition pico_hit.h:106
Raycast information.
Definition pico_hit.h:125
pv2 normal
The surface normal at the point of impact.
Definition pico_hit.h:126
pfloat dist
The distance fromt the origin to the point of impact.
Definition pico_hit.h:127
A 2D transform.
Definition pico_math.h:181
A 2D vector.
Definition pico_math.h:173
pfloat y
Definition pico_math.h:174
pfloat x
Definition pico_math.h:174