123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- #include <stdio.h>
- #include "bumpshape.h"
- #include "bad.h"
- #include "monolog.h"
- /* AABB helper functions. */
- /* X coordinate of left side of box. */
- double bumpaabb_left(BumpAABB * self) {
- return self->p.x - self->hs.x;
- }
- /* X coordinate of right side of box. */
- double bumpaabb_right(BumpAABB * self) {
- return self->p.x + self->hs.x;
- }
- /* Y coordinate of top side of box. */
- double bumpaabb_top(BumpAABB * self) {
- return self->p.y - self->hs.y;
- }
- /* X coordinate of bottom side of box. */
- double bumpaabb_down(BumpAABB * self) {
- return self->p.y + self->hs.y;
- }
- /* Full width of the box */
- double bumpaabb_width(BumpAABB * self) {
- return 2.0 * self->hs.x;
- }
- /* Full height of the box */
- double bumpaabb_height(BumpAABB * self) {
- return 2.0 * self->hs.y;
- }
- /** Makes a new bounding box. W and H are the FULL width and height of the box. */
- BumpAABB bumpaabb(double cx, double cy, double w, double h) {
- BumpAABB result = { bevec(cx, cy), bevec(w / 2.0, h / 2.0) };
- return result;
- }
- /** Makes a new bounding box with integer bounds.
- * W and H are the FULL width and height of the box.
- * And x and y are the coordinates of the top left corner. */
- BumpAABB bumpaabb_make_int(int x, int y, int w, int h) {
- double hw = ((double) w) / 2.0;
- double hh = ((double) h) / 2.0;
- double cx = ((double) x) + hw;
- double cy = ((double) y) + hh;
- return bumpaabb(cx, cy, ((double) w), ((double) h));
- }
- /* Prints a textual description of the bounds box to the file out.
- * For debugging purposes */
- void bumpaabb_print(BumpAABB * box, FILE * out) {
- double x = bumpaabb_left(box);
- double y = bumpaabb_top(box);
- double w = bumpaabb_width(box);
- double h = bumpaabb_height(box);
- fprintf(out, "[(%lf %lf) (%lf %lf)]", x, y, w, h);
- }
- BumpCircle bumpcircle(double cx, double cy, double radius) {
- BumpCircle result = { bevec(cx, cy), radius};
- return result;
- }
- BumpCircle bumpcircle_make_int(int x, int y, int radius) {
- double cx = (double)x;
- double cy = (double)y;
- double rr = (double)radius;
- return bumpcircle(cx, cy, rr);
- }
- BumpSegment bumpsegment(double x1, double y1, double x2, double y2) {
- BumpSegment result = { bevec(x1, y1), bevec(x2, y2)};
- return result;
- }
- BumpSegment bumpsegment_make_int(int x1, int y1, int x2, int y2) {
- double dx1 = ((double) x1);
- double dy1 = ((double) y1);
- double dx2 = ((double) x2);
- double dy2 = ((double) y2);
- return bumpsegment(dx1, dy1, dx2, dy2);
- }
- BumpShape bumpcircleshape(double cx, double cy, double radius) {
- BumpCircleShape aid = { BUMPSHAPE_CIRCLE, bumpcircle(cx, cy, radius) };
- BumpShape result;
- result.circle = aid;
- return result;
- }
- BumpShape bumpsegmentshape(double x1, double y1, double x2, double y2) {
- BumpSegmentShape aid = { BUMPSHAPE_SEGMENT, bumpsegment(x1, y1, x2, y2) };
- BumpShape result;
- result.segment = aid;
- return result;
- }
-
- BumpShape bumpboxshape(double cx, double cy, double w, double h) {
- BumpBoxShape aid = { BUMPSHAPE_SEGMENT, bumpaabb(cx, cy, w, h) };
- BumpShape result;
- result.box = aid;
- return result;
- }
- BumpShape bumperrorshape(int code) {
- BumpErrorShape aid = { BUMPSHAPE_ERROR, code };
- BumpShape result;
- result.error = aid;
- return result;
- }
- BumpShape bumpshape_va(int type, va_list args) {
- double cx, cy, r, x1, x2, y1, y2, w, h;
- BumpShape result;
- switch(type) {
- case BUMPSHAPE_BOX:
- x1 = va_arg(args, double);
- y1 = va_arg(args, double);
- w = va_arg(args, double);
- h = va_arg(args, double);
- return bumpboxshape(x1, y1, w, h);
- break;
-
- case BUMPSHAPE_CIRCLE:
- x1 = va_arg(args, double);
- y1 = va_arg(args, double);
- r = va_arg(args, double);
- return bumpcircleshape(x1, y1, r);
- break;
-
- case BUMPSHAPE_SEGMENT:
- x1 = va_arg(args, double);
- y1 = va_arg(args, double);
- x2 = va_arg(args, double);
- y2 = va_arg(args, double);
- return bumpsegmentshape(x1, y1, x2, y2);
- break;
-
- default:
- return bumperrorshape(-1);
- break;
- }
- }
- BumpShape bumpshape(int type, ...) {
- BumpShape result;
- va_list args;
- va_start(args, type);
- result = bumpshape_va(type, args);
- va_end(args);
- return result;
- }
- BeVec bumpcircle_bumpaabb_overlap_vector(BumpCircle c, BumpAABB b) {
- float close_x = bad_clampd(c.p.x, bumpaabb_left(&b), bumpaabb_right(&b));
- float close_y = bad_clampd(c.p.y, bumpaabb_top(&b), bumpaabb_down(&b));
- float dx = c.p.x - close_x;
- float dy = c.p.y - close_y;
- return bevec(dx, dy); /* XXX this is wrong, need c.r in there somewhere */
- }
- int bumpcircle_bumpaabb_overlap_p(BumpCircle c, BumpAABB b) {
- float close_x = bad_clampd(c.p.x, bumpaabb_left(&b), bumpaabb_right(&b));
- float close_y = bad_clampd(c.p.y, bumpaabb_top(&b), bumpaabb_down(&b));
- float dx = c.p.x - close_x;
- float dy = c.p.y - close_y;
- return (((dx*dx) + (dy*dy)) > (c.radius * c.radius));
- }
- int bumpcircleshape_bumpboxshape_overlap_p(BumpShape c, BumpShape b) {
- return bumpcircle_bumpaabb_overlap_p(c.circle.shape, b.box.shape);
- }
- /* Returns overlap of the bounds boxes of self and other in x direction.
- * May be zero or negative if no overlap.
- */
- double bumpaabb_overlap_x(BumpAABB self, BumpAABB other) {
- if (self.p.x < other.p.x) {
- return (self.hs.x + other.hs.x) + (self.p.x - other.p.x );
- } else {
- return (other.hs.x + self.hs.x) + (other.p.x - self.p.x);
- }
- }
- /* Returns overlap of the bounds boxes of self and other in y direction.
- * May be zero or negative if no overlap.
- */
- double bumpaabb_overlap_y(BumpAABB self, BumpAABB other) {
- if (self.p.y < other.p.y) {
- return (self.hs.y + other.hs.y) + (self.p.y - other.p.y );
- } else {
- return (other.hs.y + self.hs.y) + (other.p.y - self.p.y);
- }
- }
- /* Returns overlap of the bounds boxes of self and other in x direction.
- * May be zero or negative if no overlap.
- */
- double bumpaabb_overlap_x_raw(BumpAABB self, BumpAABB other) {
- return (self.hs.x + other.hs.x) + (self.p.x - other.p.x );
- }
- /* Returns overlap of the bounds boxes of self and other in y direction.
- * May be zero or negative if no overlap.
- */
- double bumpaabb_overlap_y_raw(BumpAABB self, BumpAABB other) {
- return (self.hs.y + other.hs.y) + (self.p.y - other.p.y );
- }
- /* Returns the overlap vector between two bounds boxes. */
- BeVec bumpaabb_overlap_vector(BumpAABB self, BumpAABB other) {
- return bevec(bumpaabb_overlap_x(self, other), bumpaabb_overlap_y(self, other));
- }
- /* Returns whether or not there is overlap between two bounds boxes. */
- int bumpaabb_overlap_p(BumpAABB self, BumpAABB other) {
- if (bumpaabb_overlap_x(self, other) < 0) return FALSE;
- return (bumpaabb_overlap_y(self, other) > 0);
- }
- /* Helper struct to determine which function to use when colliding two
- * shapes.
- */
- struct BumpShapeCollider_ {
- int swap;
- int (*collide)(BumpShape * me, BumpShape * you);
- };
- int bumpboxshape_bumpboxshape_overlap_p(BumpShape * me, BumpShape * you) {
- return bumpaabb_overlap_p(me->box.shape, you->box.shape);
- }
- int bumpboxshape_bumpcircleshape_overlap_p(BumpShape * me, BumpShape * you) {
- return bumpcircle_bumpaabb_overlap_p(you->circle.shape, me->box.shape);
- }
- int bumpboxshape_bumpsegmentshape_overlap_p(BumpShape * me, BumpShape * you) {
- (void) me; (void) you; return 0;
- }
- int bumpcircleshape_bumpcircleshape_overlap_p(BumpShape * me, BumpShape * you) {
- (void) me; (void) you; return 0;
- }
- int bumpcircleshape_bumpsegmentshape_overlap_p(BumpShape * me, BumpShape * you) {
- (void) me; (void) you; return 0;
- }
- int bumpsegmentshape_bumpsegmentshape_overlap_p (BumpShape * me, BumpShape * you) {
- (void) me; (void) you; return 0;
- }
- typedef struct BumpShapeCollider_ BumpShapeCollider;
-
- /* Dispatch table. */
- static BumpShapeCollider bumpshape_colliders[BUMPSHAPE_MAX][BUMPSHAPE_MAX] = {
- /* BUMPSHAPE_BOX VS */
- {
- /* BUMPSHAPE_BOX */ { 0, bumpboxshape_bumpboxshape_overlap_p },
- /* BUMPSHAPE_CIRCLE */ { 0, bumpboxshape_bumpcircleshape_overlap_p },
- /* BUMPSHAPE_SEGMENT */ { 0, bumpboxshape_bumpsegmentshape_overlap_p },
- },
- /* BUMPSHAPE_CIRCLE VS */
- {
- /* BUMPSHAPE_BOX */ { 1, bumpboxshape_bumpcircleshape_overlap_p },
- /* BUMPSHAPE_CIRCLE */ { 0, bumpcircleshape_bumpcircleshape_overlap_p },
- /* BUMPSHAPE_SEGMENT */ { 0, bumpcircleshape_bumpsegmentshape_overlap_p },
- },
- /* BUMPSHAPE_SEGMENT VS */
- {
- /* BUMPSHAPE_BOX */ { 1, bumpboxshape_bumpsegmentshape_overlap_p },
- /* BUMPSHAPE_CIRCLE */ { 1, bumpcircleshape_bumpsegmentshape_overlap_p },
- /* BUMPSHAPE_SEGMENT */ { 0, bumpsegmentshape_bumpsegmentshape_overlap_p},
- }
- };
- BumpShapeCollider * bumpshape_collider_for(BumpShape * me, BumpShape * you) {
- if (!me) return NULL;
- if (!you) return NULL;
- if (me->header.type >= BUMPSHAPE_MAX) return NULL;
- if (you->header.type >= BUMPSHAPE_MAX) return NULL;
- if (me->header.type < 0) return NULL;
- if (you->header.type < 0) return NULL;
- return bumpshape_colliders[me->header.type] + you->header.type;
- }
-
- int bumpshape_overlap_p(BumpShape * me, BumpShape * you) {
- BumpShapeCollider * collider = bumpshape_collider_for(me, you);
- BumpShape * aid;
- if (!collider) {
- LOG_ERROR("Cannot collide shapes: %p %p!", me, you);
- return 0;
- }
- if (collider->swap) {
- return collider->collide(you, me);
- }
- return collider->collide(me, you);
- }
|