bumpshape.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #include <stdio.h>
  2. #include "bumpshape.h"
  3. #include "bad.h"
  4. #include "monolog.h"
  5. /* AABB helper functions. */
  6. /* X coordinate of left side of box. */
  7. double bumpaabb_left(BumpAABB * self) {
  8. return self->p.x - self->hs.x;
  9. }
  10. /* X coordinate of right side of box. */
  11. double bumpaabb_right(BumpAABB * self) {
  12. return self->p.x + self->hs.x;
  13. }
  14. /* Y coordinate of top side of box. */
  15. double bumpaabb_top(BumpAABB * self) {
  16. return self->p.y - self->hs.y;
  17. }
  18. /* X coordinate of bottom side of box. */
  19. double bumpaabb_down(BumpAABB * self) {
  20. return self->p.y + self->hs.y;
  21. }
  22. /* Full width of the box */
  23. double bumpaabb_width(BumpAABB * self) {
  24. return 2.0 * self->hs.x;
  25. }
  26. /* Full height of the box */
  27. double bumpaabb_height(BumpAABB * self) {
  28. return 2.0 * self->hs.y;
  29. }
  30. /** Makes a new bounding box. W and H are the FULL width and height of the box. */
  31. BumpAABB bumpaabb(double cx, double cy, double w, double h) {
  32. BumpAABB result = { bevec(cx, cy), bevec(w / 2.0, h / 2.0) };
  33. return result;
  34. }
  35. /** Makes a new bounding box with integer bounds.
  36. * W and H are the FULL width and height of the box.
  37. * And x and y are the coordinates of the top left corner. */
  38. BumpAABB bumpaabb_make_int(int x, int y, int w, int h) {
  39. double hw = ((double) w) / 2.0;
  40. double hh = ((double) h) / 2.0;
  41. double cx = ((double) x) + hw;
  42. double cy = ((double) y) + hh;
  43. return bumpaabb(cx, cy, ((double) w), ((double) h));
  44. }
  45. /* Prints a textual description of the bounds box to the file out.
  46. * For debugging purposes */
  47. void bumpaabb_print(BumpAABB * box, FILE * out) {
  48. double x = bumpaabb_left(box);
  49. double y = bumpaabb_top(box);
  50. double w = bumpaabb_width(box);
  51. double h = bumpaabb_height(box);
  52. fprintf(out, "[(%lf %lf) (%lf %lf)]", x, y, w, h);
  53. }
  54. BumpCircle bumpcircle(double cx, double cy, double radius) {
  55. BumpCircle result = { bevec(cx, cy), radius};
  56. return result;
  57. }
  58. BumpCircle bumpcircle_make_int(int x, int y, int radius) {
  59. double cx = (double)x;
  60. double cy = (double)y;
  61. double rr = (double)radius;
  62. return bumpcircle(cx, cy, rr);
  63. }
  64. BumpSegment bumpsegment(double x1, double y1, double x2, double y2) {
  65. BumpSegment result = { bevec(x1, y1), bevec(x2, y2)};
  66. return result;
  67. }
  68. BumpSegment bumpsegment_make_int(int x1, int y1, int x2, int y2) {
  69. double dx1 = ((double) x1);
  70. double dy1 = ((double) y1);
  71. double dx2 = ((double) x2);
  72. double dy2 = ((double) y2);
  73. return bumpsegment(dx1, dy1, dx2, dy2);
  74. }
  75. BumpShape bumpcircleshape(double cx, double cy, double radius) {
  76. BumpCircleShape aid = { BUMPSHAPE_CIRCLE, bumpcircle(cx, cy, radius) };
  77. BumpShape result;
  78. result.circle = aid;
  79. return result;
  80. }
  81. BumpShape bumpsegmentshape(double x1, double y1, double x2, double y2) {
  82. BumpSegmentShape aid = { BUMPSHAPE_SEGMENT, bumpsegment(x1, y1, x2, y2) };
  83. BumpShape result;
  84. result.segment = aid;
  85. return result;
  86. }
  87. BumpShape bumpboxshape(double cx, double cy, double w, double h) {
  88. BumpBoxShape aid = { BUMPSHAPE_SEGMENT, bumpaabb(cx, cy, w, h) };
  89. BumpShape result;
  90. result.box = aid;
  91. return result;
  92. }
  93. BumpShape bumperrorshape(int code) {
  94. BumpErrorShape aid = { BUMPSHAPE_ERROR, code };
  95. BumpShape result;
  96. result.error = aid;
  97. return result;
  98. }
  99. BumpShape bumpshape_va(int type, va_list args) {
  100. double cx, cy, r, x1, x2, y1, y2, w, h;
  101. BumpShape result;
  102. switch(type) {
  103. case BUMPSHAPE_BOX:
  104. x1 = va_arg(args, double);
  105. y1 = va_arg(args, double);
  106. w = va_arg(args, double);
  107. h = va_arg(args, double);
  108. return bumpboxshape(x1, y1, w, h);
  109. break;
  110. case BUMPSHAPE_CIRCLE:
  111. x1 = va_arg(args, double);
  112. y1 = va_arg(args, double);
  113. r = va_arg(args, double);
  114. return bumpcircleshape(x1, y1, r);
  115. break;
  116. case BUMPSHAPE_SEGMENT:
  117. x1 = va_arg(args, double);
  118. y1 = va_arg(args, double);
  119. x2 = va_arg(args, double);
  120. y2 = va_arg(args, double);
  121. return bumpsegmentshape(x1, y1, x2, y2);
  122. break;
  123. default:
  124. return bumperrorshape(-1);
  125. break;
  126. }
  127. }
  128. BumpShape bumpshape(int type, ...) {
  129. BumpShape result;
  130. va_list args;
  131. va_start(args, type);
  132. result = bumpshape_va(type, args);
  133. va_end(args);
  134. return result;
  135. }
  136. BeVec bumpcircle_bumpaabb_overlap_vector(BumpCircle c, BumpAABB b) {
  137. float close_x = bad_clampd(c.p.x, bumpaabb_left(&b), bumpaabb_right(&b));
  138. float close_y = bad_clampd(c.p.y, bumpaabb_top(&b), bumpaabb_down(&b));
  139. float dx = c.p.x - close_x;
  140. float dy = c.p.y - close_y;
  141. return bevec(dx, dy); /* XXX this is wrong, need c.r in there somewhere */
  142. }
  143. int bumpcircle_bumpaabb_overlap_p(BumpCircle c, BumpAABB b) {
  144. float close_x = bad_clampd(c.p.x, bumpaabb_left(&b), bumpaabb_right(&b));
  145. float close_y = bad_clampd(c.p.y, bumpaabb_top(&b), bumpaabb_down(&b));
  146. float dx = c.p.x - close_x;
  147. float dy = c.p.y - close_y;
  148. return (((dx*dx) + (dy*dy)) > (c.radius * c.radius));
  149. }
  150. int bumpcircleshape_bumpboxshape_overlap_p(BumpShape c, BumpShape b) {
  151. return bumpcircle_bumpaabb_overlap_p(c.circle.shape, b.box.shape);
  152. }
  153. /* Returns overlap of the bounds boxes of self and other in x direction.
  154. * May be zero or negative if no overlap.
  155. */
  156. double bumpaabb_overlap_x(BumpAABB self, BumpAABB other) {
  157. if (self.p.x < other.p.x) {
  158. return (self.hs.x + other.hs.x) + (self.p.x - other.p.x );
  159. } else {
  160. return (other.hs.x + self.hs.x) + (other.p.x - self.p.x);
  161. }
  162. }
  163. /* Returns overlap of the bounds boxes of self and other in y direction.
  164. * May be zero or negative if no overlap.
  165. */
  166. double bumpaabb_overlap_y(BumpAABB self, BumpAABB other) {
  167. if (self.p.y < other.p.y) {
  168. return (self.hs.y + other.hs.y) + (self.p.y - other.p.y );
  169. } else {
  170. return (other.hs.y + self.hs.y) + (other.p.y - self.p.y);
  171. }
  172. }
  173. /* Returns overlap of the bounds boxes of self and other in x direction.
  174. * May be zero or negative if no overlap.
  175. */
  176. double bumpaabb_overlap_x_raw(BumpAABB self, BumpAABB other) {
  177. return (self.hs.x + other.hs.x) + (self.p.x - other.p.x );
  178. }
  179. /* Returns overlap of the bounds boxes of self and other in y direction.
  180. * May be zero or negative if no overlap.
  181. */
  182. double bumpaabb_overlap_y_raw(BumpAABB self, BumpAABB other) {
  183. return (self.hs.y + other.hs.y) + (self.p.y - other.p.y );
  184. }
  185. /* Returns the overlap vector between two bounds boxes. */
  186. BeVec bumpaabb_overlap_vector(BumpAABB self, BumpAABB other) {
  187. return bevec(bumpaabb_overlap_x(self, other), bumpaabb_overlap_y(self, other));
  188. }
  189. /* Returns whether or not there is overlap between two bounds boxes. */
  190. int bumpaabb_overlap_p(BumpAABB self, BumpAABB other) {
  191. if (bumpaabb_overlap_x(self, other) < 0) return FALSE;
  192. return (bumpaabb_overlap_y(self, other) > 0);
  193. }
  194. /* Helper struct to determine which function to use when colliding two
  195. * shapes.
  196. */
  197. struct BumpShapeCollider_ {
  198. int swap;
  199. int (*collide)(BumpShape * me, BumpShape * you);
  200. };
  201. int bumpboxshape_bumpboxshape_overlap_p(BumpShape * me, BumpShape * you) {
  202. return bumpaabb_overlap_p(me->box.shape, you->box.shape);
  203. }
  204. int bumpboxshape_bumpcircleshape_overlap_p(BumpShape * me, BumpShape * you) {
  205. return bumpcircle_bumpaabb_overlap_p(you->circle.shape, me->box.shape);
  206. }
  207. int bumpboxshape_bumpsegmentshape_overlap_p(BumpShape * me, BumpShape * you) {
  208. (void) me; (void) you; return 0;
  209. }
  210. int bumpcircleshape_bumpcircleshape_overlap_p(BumpShape * me, BumpShape * you) {
  211. (void) me; (void) you; return 0;
  212. }
  213. int bumpcircleshape_bumpsegmentshape_overlap_p(BumpShape * me, BumpShape * you) {
  214. (void) me; (void) you; return 0;
  215. }
  216. int bumpsegmentshape_bumpsegmentshape_overlap_p (BumpShape * me, BumpShape * you) {
  217. (void) me; (void) you; return 0;
  218. }
  219. typedef struct BumpShapeCollider_ BumpShapeCollider;
  220. /* Dispatch table. */
  221. static BumpShapeCollider bumpshape_colliders[BUMPSHAPE_MAX][BUMPSHAPE_MAX] = {
  222. /* BUMPSHAPE_BOX VS */
  223. {
  224. /* BUMPSHAPE_BOX */ { 0, bumpboxshape_bumpboxshape_overlap_p },
  225. /* BUMPSHAPE_CIRCLE */ { 0, bumpboxshape_bumpcircleshape_overlap_p },
  226. /* BUMPSHAPE_SEGMENT */ { 0, bumpboxshape_bumpsegmentshape_overlap_p },
  227. },
  228. /* BUMPSHAPE_CIRCLE VS */
  229. {
  230. /* BUMPSHAPE_BOX */ { 1, bumpboxshape_bumpcircleshape_overlap_p },
  231. /* BUMPSHAPE_CIRCLE */ { 0, bumpcircleshape_bumpcircleshape_overlap_p },
  232. /* BUMPSHAPE_SEGMENT */ { 0, bumpcircleshape_bumpsegmentshape_overlap_p },
  233. },
  234. /* BUMPSHAPE_SEGMENT VS */
  235. {
  236. /* BUMPSHAPE_BOX */ { 1, bumpboxshape_bumpsegmentshape_overlap_p },
  237. /* BUMPSHAPE_CIRCLE */ { 1, bumpcircleshape_bumpsegmentshape_overlap_p },
  238. /* BUMPSHAPE_SEGMENT */ { 0, bumpsegmentshape_bumpsegmentshape_overlap_p},
  239. }
  240. };
  241. BumpShapeCollider * bumpshape_collider_for(BumpShape * me, BumpShape * you) {
  242. if (!me) return NULL;
  243. if (!you) return NULL;
  244. if (me->header.type >= BUMPSHAPE_MAX) return NULL;
  245. if (you->header.type >= BUMPSHAPE_MAX) return NULL;
  246. if (me->header.type < 0) return NULL;
  247. if (you->header.type < 0) return NULL;
  248. return bumpshape_colliders[me->header.type] + you->header.type;
  249. }
  250. int bumpshape_overlap_p(BumpShape * me, BumpShape * you) {
  251. BumpShapeCollider * collider = bumpshape_collider_for(me, you);
  252. BumpShape * aid;
  253. if (!collider) {
  254. LOG_ERROR("Cannot collide shapes: %p %p!", me, you);
  255. return 0;
  256. }
  257. if (collider->swap) {
  258. return collider->collide(you, me);
  259. }
  260. return collider->collide(me, you);
  261. }