moved shape overlap code to collision.c
This commit is contained in:
parent
6f49f846cc
commit
59f6c7d1ee
88
src/collision.c
Normal file
88
src/collision.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include "collision.h"
|
||||
#include "player.h"
|
||||
|
||||
// =====================================================
|
||||
// Shape overlap test using the separating axis theorem
|
||||
// =====================================================
|
||||
|
||||
typedef struct Range {float min; float max; } Range;
|
||||
|
||||
static
|
||||
Range _shape_get_range_on_axis(PhysicsEntity self, Vector axis) {
|
||||
Vector point = shape_get_point_transformed(self.tc->get_shape(self.data), 0, *self.transformable->get_transform(self.data));
|
||||
float dot = vdotf(axis, point);
|
||||
Range range = {dot, dot};
|
||||
|
||||
for(size_t point_index = 1; point_index < shape_get_points_count(self.tc->get_shape(self.data)); ++point_index) {
|
||||
point = shape_get_point_transformed(self.tc->get_shape(self.data), point_index, *self.transformable->get_transform(self.data));
|
||||
dot = vdotf(axis, point);
|
||||
if(dot < range.min)
|
||||
range.min = fminf(dot, range.min);
|
||||
if(dot > range.max)
|
||||
range.max = fmaxf(dot, range.max);
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
static
|
||||
Vector _shape_overlap_on_axis(PhysicsEntity self, PhysicsEntity other, Vector axis) {
|
||||
Range a_range = _shape_get_range_on_axis(self, axis);
|
||||
Range b_range = _shape_get_range_on_axis(other, axis);
|
||||
|
||||
if(a_range.min <= b_range.max && b_range.min <= b_range.max)
|
||||
return vmulff(axis, fminf(b_range.max - b_range.min, b_range.min - a_range.max));
|
||||
else
|
||||
return ZeroVector;
|
||||
}
|
||||
|
||||
static
|
||||
Collision _shape_get_overlap_internal(PhysicsEntity self, PhysicsEntity other) {
|
||||
// The shortest escape vector found so far
|
||||
Vector shortest_escape = InfinityVector;
|
||||
// the squared length of the shortest escape vector found so far
|
||||
float shortest_sqrmag = INFINITY;
|
||||
// the first index of the points on the edge
|
||||
size_t shortest_escape_edge = 0;
|
||||
// the number of points in the shape of self
|
||||
size_t self_point_count = shape_get_points_count(self.tc->get_shape(self.data));
|
||||
|
||||
for(size_t point_index = 0; point_index < self_point_count; ++point_index) {
|
||||
// the next point on the line
|
||||
size_t next_index = (point_index + 1) % self_point_count;
|
||||
// get the two points defining the collision edge
|
||||
Vector a = shape_get_point_transformed(self.tc->get_shape(self.data), point_index, *self.transformable->get_transform(self.data));
|
||||
Vector b = shape_get_point_transformed(self.tc->get_shape(self.data), next_index, *self.transformable->get_transform(self.data));
|
||||
// the direction of the line
|
||||
Vector diff = vsubf(b, a);
|
||||
|
||||
// the smallest escape vector on this axis
|
||||
Vector escape = _shape_overlap_on_axis(self, other, vnormalizedf(diff));
|
||||
float sqr_mag = vsqrmagnitudef(escape);
|
||||
if(sqr_mag < shortest_sqrmag) {
|
||||
shortest_sqrmag = sqr_mag;
|
||||
shortest_escape = escape;
|
||||
shortest_escape_edge = point_index;
|
||||
}
|
||||
}
|
||||
|
||||
RigidBody* rba = self.tc->get_rigidbody(self.data);
|
||||
RigidBody* rbb = self.tc->get_rigidbody(self.data);
|
||||
|
||||
return (Collision) {
|
||||
.edge_left = shortest_escape_edge,
|
||||
.edge_right = (1 + shortest_escape_edge) % self_point_count,
|
||||
.normal = vnormalizedf(shortest_escape),
|
||||
.velocity = vsubf(rigidbody_get_velocity(rba), rigidbody_get_velocity(rbb)),
|
||||
.other = other,
|
||||
.separation_force = shortest_escape
|
||||
};
|
||||
}
|
||||
|
||||
Collision get_collision(PhysicsEntity a, PhysicsEntity b) {
|
||||
Collision self_first = _shape_get_overlap_internal(a, b);
|
||||
Collision other_first = _shape_get_overlap_internal(b, a);
|
||||
return vsqrmagnitudef(self_first.separation_force) < vsqrmagnitudef(other_first.separation_force)
|
||||
? self_first
|
||||
: other_first;
|
||||
}
|
63
src/shape.c
63
src/shape.c
|
@ -173,66 +173,3 @@ Vector shape_get_median_point(Shape* self) {
|
|||
int shape_is_convex(Shape* self) {
|
||||
return self->is_convex;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// Shape overlap test using the separating axis theorem
|
||||
// =====================================================
|
||||
|
||||
typedef struct Range {float min; float max; } Range;
|
||||
|
||||
static
|
||||
Range _shape_get_range_on_axis(Shape* self, Transform self_transform, Vector axis) {
|
||||
Vector point = shape_get_point_transformed(self, 0, self_transform);
|
||||
float dot = vdotf(axis, point);
|
||||
Range range = {dot, dot};
|
||||
|
||||
for(size_t point_index = 1; point_index < self->points_len; ++point_index) {
|
||||
point = shape_get_point_transformed(self, point_index, self_transform);
|
||||
dot = vdotf(axis, point);
|
||||
if(dot < range.min)
|
||||
range.min = fminf(dot, range.min);
|
||||
if(dot > range.max)
|
||||
range.max = fmaxf(dot, range.max);
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
static
|
||||
Vector _shape_overlap_on_axis(Shape* self, Transform self_transform, Shape* other, Transform other_transform, Vector axis) {
|
||||
Range a_range = _shape_get_range_on_axis(self, self_transform, axis);
|
||||
Range b_range = _shape_get_range_on_axis(other, other_transform, axis);
|
||||
|
||||
if(a_range.min <= b_range.max && b_range.min <= b_range.max)
|
||||
return vmulff(axis, fminf(b_range.max - b_range.min, b_range.min - a_range.max));
|
||||
else
|
||||
return ZeroVector;
|
||||
}
|
||||
|
||||
static
|
||||
Vector _shape_get_overlap_internal(Shape* self, Transform self_transform, Shape* other, Transform other_transform) {
|
||||
Vector shortest_escape = InfinityVector;
|
||||
float shortest_sqrmag = INFINITY;
|
||||
|
||||
for(size_t point_index = 0; point_index < self->points_len; ++point_index) {
|
||||
size_t next_index = (point_index + 1) % self->points_len;
|
||||
Vector a = shape_get_point_transformed(self, point_index, self_transform);
|
||||
Vector b = shape_get_point_transformed(self, next_index, other_transform);
|
||||
Vector diff = vsubf(b, a);
|
||||
|
||||
Vector escape = _shape_overlap_on_axis(self, self_transform, other, other_transform, vnormalizedf(diff));
|
||||
float sqr_mag = vsqrmagnitudef(escape);
|
||||
if(sqr_mag < shortest_sqrmag) {
|
||||
shortest_sqrmag = sqr_mag;
|
||||
shortest_escape = escape;
|
||||
}
|
||||
}
|
||||
|
||||
return shortest_escape;
|
||||
}
|
||||
|
||||
Vector shape_get_overlap(Shape* self, Transform self_transform, Shape* other, Transform other_transform) {
|
||||
Vector self_first = _shape_get_overlap_internal(self, self_transform, other, other_transform);
|
||||
Vector other_first = _shape_get_overlap_internal(other, other_transform, self, self_transform);
|
||||
return vsqrmagnitudef(self_first) < vsqrmagnitudef(other_first) ? self_first : other_first;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,4 @@ extern Vector shape_remove_point(Shape* self, size_t at);
|
|||
extern Vector shape_get_median_point(Shape* self);
|
||||
extern int shape_is_convex(Shape* self);
|
||||
|
||||
extern Vector shape_get_overlap(Shape* self, Transform self_transform, Shape* other, Transform other_transform);
|
||||
|
||||
#endif // !_fencer_shape_h
|
||||
|
|
Loading…
Reference in a new issue