prosperon/source/engine/thirdparty/Chipmunk2D/src/cpSpaceQuery.c

247 lines
7.2 KiB
C
Raw Normal View History

2022-01-19 16:43:21 -06:00
/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "chipmunk/chipmunk_private.h"
//MARK: Nearest Point Query Functions
struct PointQueryContext {
cpVect point;
cpFloat maxDistance;
cpShapeFilter filter;
cpSpacePointQueryFunc func;
};
static cpCollisionID
NearestPointQuery(struct PointQueryContext *context, cpShape *shape, cpCollisionID id, void *data)
{
if(
!cpShapeFilterReject(shape->filter, context->filter)
){
cpPointQueryInfo info;
cpShapePointQuery(shape, context->point, &info);
if(info.shape && info.distance < context->maxDistance) context->func(shape, info.point, info.distance, info.gradient, data);
}
return id;
}
void
cpSpacePointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpSpacePointQueryFunc func, void *data)
{
struct PointQueryContext context = {point, maxDistance, filter, func};
cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));
cpSpaceLock(space); {
cpSpatialIndexQuery(space->dynamicShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);
cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);
} cpSpaceUnlock(space, cpTrue);
}
static cpCollisionID
NearestPointQueryNearest(struct PointQueryContext *context, cpShape *shape, cpCollisionID id, cpPointQueryInfo *out)
{
if(
!cpShapeFilterReject(shape->filter, context->filter) && !shape->sensor
){
cpPointQueryInfo info;
cpShapePointQuery(shape, context->point, &info);
if(info.distance < out->distance) (*out) = info;
}
return id;
}
cpShape *
cpSpacePointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpPointQueryInfo *out)
{
cpPointQueryInfo info = {NULL, cpvzero, maxDistance, cpvzero};
if(out){
(*out) = info;
} else {
out = &info;
}
struct PointQueryContext context = {
point, maxDistance,
filter,
NULL
};
cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));
cpSpatialIndexQuery(space->dynamicShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);
cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);
return (cpShape *)out->shape;
}
//MARK: Segment Query Functions
struct SegmentQueryContext {
cpVect start, end;
cpFloat radius;
cpShapeFilter filter;
cpSpaceSegmentQueryFunc func;
};
static cpFloat
SegmentQuery(struct SegmentQueryContext *context, cpShape *shape, void *data)
{
cpSegmentQueryInfo info;
if(
!cpShapeFilterReject(shape->filter, context->filter) &&
cpShapeSegmentQuery(shape, context->start, context->end, context->radius, &info)
){
context->func(shape, info.point, info.normal, info.alpha, data);
}
return 1.0f;
}
void
cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSpaceSegmentQueryFunc func, void *data)
{
struct SegmentQueryContext context = {
start, end,
radius,
filter,
func,
};
cpSpaceLock(space); {
cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);
cpSpatialIndexSegmentQuery(space->dynamicShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);
} cpSpaceUnlock(space, cpTrue);
}
static cpFloat
SegmentQueryFirst(struct SegmentQueryContext *context, cpShape *shape, cpSegmentQueryInfo *out)
{
cpSegmentQueryInfo info;
if(
!cpShapeFilterReject(shape->filter, context->filter) && !shape->sensor &&
cpShapeSegmentQuery(shape, context->start, context->end, context->radius, &info) &&
info.alpha < out->alpha
){
(*out) = info;
}
return out->alpha;
}
cpShape *
cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSegmentQueryInfo *out)
{
cpSegmentQueryInfo info = {NULL, end, cpvzero, 1.0f};
if(out){
(*out) = info;
} else {
out = &info;
}
struct SegmentQueryContext context = {
start, end,
radius,
filter,
NULL
};
cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);
cpSpatialIndexSegmentQuery(space->dynamicShapes, &context, start, end, out->alpha, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);
return (cpShape *)out->shape;
}
//MARK: BB Query Functions
struct BBQueryContext {
cpBB bb;
cpShapeFilter filter;
cpSpaceBBQueryFunc func;
};
static cpCollisionID
BBQuery(struct BBQueryContext *context, cpShape *shape, cpCollisionID id, void *data)
{
if(
!cpShapeFilterReject(shape->filter, context->filter) &&
cpBBIntersects(context->bb, shape->bb)
){
context->func(shape, data);
}
return id;
}
void
cpSpaceBBQuery(cpSpace *space, cpBB bb, cpShapeFilter filter, cpSpaceBBQueryFunc func, void *data)
{
struct BBQueryContext context = {bb, filter, func};
cpSpaceLock(space); {
cpSpatialIndexQuery(space->dynamicShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);
cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);
} cpSpaceUnlock(space, cpTrue);
}
//MARK: Shape Query Functions
struct ShapeQueryContext {
cpSpaceShapeQueryFunc func;
void *data;
cpBool anyCollision;
};
// Callback from the spatial hash.
static cpCollisionID
ShapeQuery(cpShape *a, cpShape *b, cpCollisionID id, struct ShapeQueryContext *context)
{
if(cpShapeFilterReject(a->filter, b->filter) || a == b) return id;
cpContactPointSet set = cpShapesCollide(a, b);
if(set.count){
if(context->func) context->func(b, &set, context->data);
context->anyCollision = !(a->sensor || b->sensor);
}
return id;
}
cpBool
cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data)
{
cpBody *body = shape->body;
cpBB bb = (body ? cpShapeUpdate(shape, body->transform) : shape->bb);
struct ShapeQueryContext context = {func, data, cpFalse};
cpSpaceLock(space); {
cpSpatialIndexQuery(space->dynamicShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);
cpSpatialIndexQuery(space->staticShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);
} cpSpaceUnlock(space, cpTrue);
return context.anyCollision;
}