bump.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430
  1. #include <math.h>
  2. #include "eruta.h"
  3. #include "camera.h"
  4. #include "callrb.h"
  5. #include "bump.h"
  6. #include "bumpshape.h"
  7. #include "mem.h"
  8. #include "dynar.h"
  9. #include "state.h"
  10. #include "draw.h"
  11. #include "monolog.h"
  12. /**
  13. * Some design ideas:
  14. *
  15. * ATTACKS: attacks are modelled as hulls that are attached
  16. * to the world and body of the attacking thing and set to a
  17. * kind of BUMP_KIND_SENSOR | BUMP_KIND_ATTACK.
  18. *
  19. * Such hulls do collide but do not cause a physical response,
  20. * only the script is notified of the attack hitting home.
  21. * Maybe some flags need to be set or would be helpful to be set as well?
  22. *
  23. * Same idea could be used to improve the current search, with a kind of
  24. * BUMP_KIND_SENSOR | BUMP_KIND_SEARCH.
  25. *
  26. * To avoid too many memory allocations, it might be a good idea to
  27. * let each Thing allocate a few hulls for attack and search, and then reuse
  28. * them. That would require an additional BUMP_FLAG_DISABLED flag.
  29. *
  30. * Problem with this idea: what about mobile atacs and projectiles, like arrows,
  31. * gun shots or rays? Perhaps attacks should be better modeled as linked Things
  32. * in stead? But even in that case such a thing would still need a sensor hull.
  33. *
  34. * Also, the advantage of using a Thing for even non-ranged attacks is that
  35. * then a sprite animation can be used to "show" the attack.
  36. * And since a thing can have multiple hulls, this can be used for "split"
  37. * attacks. So things for attacks it is!
  38. *
  39. */
  40. enum BumpLock_ {
  41. BUMP_LOCK_NORTH = 1 << 0,
  42. BUMP_LOCK_WEST = 1 << 1,
  43. BUMP_LOCK_SOUTH = 1 << 2,
  44. BUMP_LOCK_EAST = 1 << 3,
  45. };
  46. struct BumpBody_ {
  47. int id;
  48. BeVec p;
  49. BeVec v;
  50. BeVec a;
  51. BeVec p_impulse;
  52. BeVec v_impulse;
  53. BeVec a_impulse;
  54. BeVec p_next;
  55. BeVec v_next;
  56. BeVec a_next;
  57. BeVec f;
  58. float m;
  59. int locks;
  60. void *data;
  61. };
  62. struct BumpHull_ {
  63. int id;
  64. BumpBody * body;
  65. BeVec delta;
  66. /* Use bumphull_aabb_real, NOT bounds in most cases. */
  67. BumpAABB bounds;
  68. int layers;
  69. /* Type of hull */
  70. int kind;
  71. int support;
  72. /* Flags of the hull. */
  73. int flags;
  74. /* Group of the hull. Hulls in the same srictly positive group do not collide.
  75. * Zero or negative groups have no effect. The group is set to 0 by default
  76. */
  77. int group;
  78. };
  79. typedef struct BumpHash_ BumpHash;
  80. typedef struct BumpHashElement_ BumpHashElement;
  81. typedef struct BumpHashBucket_ BumpHashBucket;
  82. /* Elemenst to store in a BumpHash spatial hash table. */
  83. struct BumpHashElement_ {
  84. BumpHashElement * next;
  85. void * data;
  86. int mult_x;
  87. int mult_y;
  88. int tile_x;
  89. int tile_y;
  90. };
  91. /* A Hash bucket. */
  92. struct BumpHashBucket_ {
  93. struct BumpHashElement_ * element;
  94. int size;
  95. };
  96. /* Spacial hashing with a twist: so the size of the table can stay constant,
  97. * the virtual grid of the hash is "repeated" in the x and Y direction.
  98. * This means that very distant objects can be together in one hash cell, however,
  99. * it should still be fast to do collision since a multiplier is set, and if that
  100. * isn't equal, the far-away object cqn be filtered out.
  101. */
  102. #define BUMPHASH_TILE_W 64
  103. #define BUMPHASH_TILE_H 64
  104. #define BUMPHASH_GRID_W 64
  105. #define BUMPHASH_GRID_H 64
  106. #define BUMPHASH_BUCKETS ((BUMPHASH_GRID_W)*(BUMPHASH_GRID_H))
  107. #define BUMPHASH_W ((BUMPHASH_GRID_W)*(BUMPHASH_TILE_W))
  108. #define BUMPHASH_H ((BUMPHASH_GRID_H)*(BUMPHASH_TILE_H))
  109. #define BUMP_WORLD_MAXBODIES 1000
  110. #define BUMP_WORLD_MAXHULLS 5000
  111. #define BUMPHASH_ELEMENTS 5000
  112. struct BumpHash_ {
  113. /* Elements. */
  114. BumpHashElement elements[BUMPHASH_ELEMENTS];
  115. int last_element;
  116. /* Buckets. */
  117. BumpHashBucket buckets[BUMPHASH_BUCKETS];
  118. };
  119. BumpHash * bumphash_empty(BumpHash * self) {
  120. int index;
  121. if (!self) return NULL;
  122. self->last_element = 0;
  123. for(index = 0; index < BUMPHASH_BUCKETS; index++) {
  124. BumpHashBucket * bucket = self->buckets + index;
  125. bucket->element = NULL;
  126. bucket->size = 0;
  127. }
  128. for(index = 0; index < BUMPHASH_ELEMENTS; index++) {
  129. BumpHashElement * element = self->elements + index;
  130. element->data = NULL;
  131. element->next = NULL;
  132. element->mult_x = -1;
  133. element->mult_x = -1;
  134. }
  135. return self;
  136. };
  137. BumpHash * bumphash_init(BumpHash * self) {
  138. return bumphash_empty(self);
  139. }
  140. BumpHashElement *
  141. bumphashelement_init(BumpHashElement * element, int x, int y, void * data) {
  142. element->data = data;
  143. element->tile_x = x / BUMPHASH_W;
  144. element->tile_y = y / BUMPHASH_H;
  145. element->mult_x = x % BUMPHASH_W;
  146. element->mult_y = y % BUMPHASH_H;
  147. return element;
  148. }
  149. int bumphash_index(BumpHash * self, int x, int y) {
  150. int index = x / BUMPHASH_W;
  151. index += (y / BUMPHASH_H) * BUMPHASH_GRID_W;
  152. /* convert 2d index to 1d index. */
  153. (void) self;
  154. return index;
  155. }
  156. BumpHashBucket * bumphash_getbucket(BumpHash * self, int x, int y) {
  157. int index = bumphash_index(self, x, y);
  158. return self->buckets + index;
  159. }
  160. BumpHashElement * bumphash_add(BumpHash * self, int x, int y, void * data) {
  161. int index;
  162. BumpHashElement * element, *next_element;
  163. BumpHashBucket * bucket;
  164. if (self->last_element >= BUMPHASH_ELEMENTS) {
  165. return NULL;
  166. }
  167. element = self->elements + self->last_element;
  168. bumphashelement_init(element, x, y, data);
  169. bucket = bumphash_getbucket(self, x, y);
  170. next_element = bucket->element;
  171. element->next = next_element;
  172. bucket->element = element;
  173. return element;
  174. }
  175. /* First bump hash element. Use bumphashelement_next_at to get other objects in the same location.
  176. * That are linked to this one.
  177. */
  178. BumpHashElement * bumphash_getelement(BumpHash * self, int x, int y) {
  179. BumpHashElement * element;
  180. BumpHashBucket * bucket;
  181. bucket = bumphash_getbucket(self, x, y);
  182. return bucket->element;
  183. }
  184. int bumphashelement_ok(BumpHashElement * self, int x, int y) {
  185. int mult_x = x % BUMPHASH_W;
  186. int mult_y = y % BUMPHASH_H;
  187. return ((self->mult_x == mult_x) && (self->mult_y == mult_y));
  188. }
  189. struct BumpWorld_ {
  190. Dynar * bodies;
  191. Dynar * hulls;
  192. int body_max;
  193. int hull_max;
  194. Tilemap * map;
  195. BumpHash hash;
  196. };
  197. /** Allocates a physical body. */
  198. BumpBody * bumpbody_alloc() {
  199. return STRUCT_ALLOC(BumpBody);
  200. }
  201. /** Initializes a physical body. */
  202. BumpBody * bumpbody_init(BumpBody * self, BeVec p, double mass) {
  203. if(!self) return NULL;
  204. self->a = bevec0();
  205. self->a_impulse = bevec0();
  206. self->a_next = bevec0();
  207. self->v = bevec0();
  208. self->v_impulse = bevec0();
  209. self->v_next = bevec0();
  210. self->p_impulse = bevec0();
  211. self->p_next = bevec0();
  212. self->f = bevec0();
  213. self->p = p;
  214. self->m = mass;
  215. self->id = -1;
  216. self->locks = FALSE;
  217. self->data = NULL;
  218. return self;
  219. }
  220. /* Allocates and initializes a body. */
  221. BumpBody * bumpbody_new(BeVec p, double mass) {
  222. return bumpbody_init(bumpbody_alloc(), p, mass);
  223. }
  224. BumpBody * bumpbody_done(BumpBody * self) {
  225. if(!self) return self;
  226. self->m = 0.0;
  227. self->id = -1;
  228. return self;
  229. }
  230. BumpBody * bumpbody_free(BumpBody * self) {
  231. bumpbody_done(self);
  232. return mem_free(self);
  233. }
  234. BeVec bumpbody_p(BumpBody * self) {
  235. return self->p;
  236. }
  237. BeVec bumpbody_v(BumpBody * self) {
  238. return self->v;
  239. }
  240. BeVec bumpbody_a(BumpBody * self) {
  241. return self->a;
  242. }
  243. /* Gets data of body. In essence, this should be the Thing that owns the body. */
  244. void * bumpbody_data(BumpBody * self) {
  245. return self->data;
  246. }
  247. /* Sets data of body. In essence, this should be the Thing that owns the body. */
  248. void bumpbody_data_(BumpBody * self, void * data) {
  249. self->data = data;
  250. }
  251. BeVec bumpbody_p_(BumpBody * self, BeVec vec) {
  252. return self->p = vec;
  253. }
  254. BeVec bumpbody_v_(BumpBody * self, BeVec vec) {
  255. self->v = vec;
  256. return self->v;
  257. }
  258. BeVec bumpbody_a_(BumpBody * self, BeVec vec) {
  259. return self->a = vec;
  260. }
  261. BeVec bumpbody_p_impulse(BumpBody * self, BeVec v) {
  262. return self->p_impulse = v;
  263. }
  264. BeVec bumpbody_v_impulse(BumpBody * self, BeVec v) {
  265. return self->v_impulse = v;
  266. }
  267. BeVec bumpbody_a_impulse(BumpBody * self, BeVec v) {
  268. return self->a_impulse = v;
  269. }
  270. void bumpbody_applyforce(BumpBody * self, BeVec v) {
  271. if (!self) return;
  272. self->f = bevec_add(self->f, v);
  273. }
  274. void bumpbody_applyimpulse(BumpBody * self, BeVec v) {
  275. if (!self) return;
  276. self->p_impulse = bevec_add(self->p_impulse, v);
  277. }
  278. void bumpbody_resetforces(BumpBody * self) {
  279. self->f = bevec0();
  280. }
  281. BumpHull * bumphull_alloc() {
  282. BumpHull * hull = STRUCT_ALLOC(BumpHull);
  283. return hull;
  284. }
  285. /* Initializes a collision hull. */
  286. BumpHull * bumphull_initall(
  287. BumpHull * self, BumpBody * body, BeVec delta,
  288. BumpAABB bounds, int layers, int kind
  289. ) {
  290. if(!self) return NULL;
  291. self->body = body;
  292. self->delta = delta;
  293. self->bounds = bounds;
  294. self->layers = layers;
  295. self->kind = kind;
  296. self->id = -1;
  297. self->support = FALSE;
  298. self->flags = BUMP_FLAG_NORMAL;
  299. self->group = 0;
  300. return self;
  301. }
  302. /* Returns the true if the hull is "supported", that is, if there was
  303. * any non-null tile under it last time the world was updates.
  304. * Return false if not.
  305. */
  306. int bumphull_support(BumpHull * self) {
  307. return self->support;
  308. }
  309. /* Sets the hull's support state */
  310. int bumphull_support_(BumpHull * self, int level) {
  311. return self->support = level;
  312. }
  313. /* Initializes a collision hull. */
  314. BumpHull * bumphull_init(BumpHull * self, BumpBody * body, BumpAABB bounds) {
  315. return bumphull_initall(self, body, bevec0(), bounds, 1, -1);
  316. }
  317. BumpHull * bumphull_newall(
  318. BumpBody * body, BeVec delta, BumpAABB bounds, int layers, int kind
  319. ) {
  320. return bumphull_initall(bumphull_alloc(), body, delta, bounds, layers, kind);
  321. }
  322. BumpHull * bumphull_new(BumpBody * body, BumpAABB bounds) {
  323. return bumphull_init(bumphull_alloc(), body, bounds);
  324. }
  325. BumpHull * bumphull_done(BumpHull * self) {
  326. /* Do not deallocate the body, it's a weak reference only. */
  327. if(!self) return NULL;
  328. self->body = NULL;
  329. return self;
  330. }
  331. /** Sets the layers of a bumphull */
  332. BumpHull * bumphull_layers_(BumpHull * hull, int layers) {
  333. if(!hull) return NULL;
  334. hull->layers = layers;
  335. return hull;
  336. }
  337. /** Gets the layers of a bumphull. Returns negative on error.*/
  338. int bumphull_layers(BumpHull * hull) {
  339. if (!hull) return -1;
  340. return hull->layers;
  341. }
  342. /** Sets the kind of a bumphull. */
  343. BumpHull * bumphull_kind_(BumpHull * hull, int kind) {
  344. if(!hull) return NULL;
  345. hull->kind = kind;
  346. return hull;
  347. }
  348. /** Gets the kind of a bumphull. Returns negative on error.*/
  349. int bumphull_kind(BumpHull * hull) {
  350. if (!hull) return -1;
  351. return hull->kind;
  352. }
  353. /** Gets the ID or index of a bumphull. Returns negative on error.*/
  354. int bumphull_id(BumpHull * hull) {
  355. if (!hull) return -1;
  356. return hull->id;
  357. }
  358. /** Gets the bounds box of the bump hull. */
  359. BumpAABB bumphull_aabb(BumpHull * hull) {
  360. return hull->bounds;
  361. }
  362. /** Gets a pointer to the the bounds box of the bump hull. */
  363. BumpAABB * bumphull_aabbptr(BumpHull * hull) {
  364. return &(hull->bounds);
  365. }
  366. /** Gets the bounds box of the bump hull and moves it to the
  367. * correct position relative to the hull's body (if any).
  368. */
  369. BumpAABB bumphull_aabb_real(BumpHull * hull) {
  370. BumpAABB bounds = hull->bounds;
  371. if (hull->body) {
  372. bounds.p = bevec_add(hull->body->p, hull->delta);
  373. } else {
  374. bounds.p = hull->delta;
  375. }
  376. return bounds;
  377. }
  378. /** Gets the bounds box of the bump hull and moves it to the
  379. * correct position relative to NEXT position of the the hull's body (if any).
  380. */
  381. BumpAABB bumphull_aabb_next(BumpHull * hull) {
  382. BumpAABB bounds = hull->bounds;
  383. if (hull->body) {
  384. bounds.p = bevec_add(hull->body->p_next, hull->delta);
  385. } else {
  386. bounds.p = hull->delta;
  387. }
  388. return bounds;
  389. }
  390. /**
  391. * Returns a pointer the physical body of the hull if set, or NULL.
  392. */
  393. BumpBody * bumphull_body(BumpHull * hull) {
  394. if (!hull) return NULL;
  395. return hull->body;
  396. }
  397. /** Returns a pointer to the data of the body of the hull.
  398. * This should be the Thing that owns that body. Returns NULL
  399. * if no body or body data is set. */
  400. void * bumphull_body_data(BumpHull * hull) {
  401. return bumpbody_data(bumphull_body(hull));
  402. }
  403. /* Determines the lock flags to set for a given push back vector. */
  404. int bevec_lock_flags(BeVec vec) {
  405. int lock = 0;
  406. if (vec.x > 0.0) lock |= BUMP_LOCK_WEST;
  407. if (vec.x < 0.0) lock |= BUMP_LOCK_EAST;
  408. if (vec.y > 0.0) lock |= BUMP_LOCK_NORTH;
  409. if (vec.y < 0.0) lock |= BUMP_LOCK_SOUTH;
  410. return lock;
  411. }
  412. /* Applies the locks to vec to avoid any motion in the locked directions indicated by lock. */
  413. BeVec bevec_lock(BeVec vec, int lock) {
  414. BeVec res = vec;
  415. if (((lock & BUMP_LOCK_WEST) == BUMP_LOCK_WEST) && (vec.x < 0.0)) res.x = 0.0;
  416. if (((lock & BUMP_LOCK_EAST) == BUMP_LOCK_EAST) && (vec.x > 0.0)) res.x = 0.0;
  417. if (((lock & BUMP_LOCK_NORTH) == BUMP_LOCK_NORTH) && (vec.y < 0.0)) res.y = 0.0;
  418. if (((lock & BUMP_LOCK_SOUTH) == BUMP_LOCK_SOUTH) && (vec.y > 0.0)) res.y = 0.0;
  419. return res;
  420. }
  421. /* Calculate the collision pushback vector. */
  422. BeVec bumpaabb_collision_pushback(BumpAABB self, BumpAABB other, BeVec motion, double dt) {
  423. BeVec overlap = bumpaabb_overlap_vector(self, other);
  424. double angle = bevec_toangle(motion);
  425. BeVec dp = bevec_sub(other.p, self.p);
  426. double aidx = 0.0, aidy = 0.0;
  427. double fx, fy, vn;
  428. BeVec res = bevec0();
  429. BeVec step = bevec_mul(motion, dt);
  430. if (bevec_length(motion) < 0.01) {
  431. step = bevec_sub(other.p, self.p);
  432. angle = bevec_toangle(step);
  433. }
  434. /* Calculate the normal speed. Do not resolve collision if
  435. * objects are already moving away from each other. The advantage of
  436. * this is that objects that are moving away and that would be pushed
  437. * back by collision resolution might jump back too far. It also seems
  438. * to have some stabilizing side effects.
  439. */
  440. vn = bevec_dot(step, dp);
  441. if (vn < 0.0) { return res; }
  442. /* Calculate overlap based push back vector. */
  443. fx = 1.0;
  444. if (step.x < 0.0) {
  445. aidx = bumpaabb_overlap_x(self, other);
  446. } else if (step.x > 0.0) {
  447. aidx = bumpaabb_overlap_x(self, other);
  448. fx = -1.0;
  449. } else {
  450. fx = -1.0;
  451. aidx = bumpaabb_overlap_x(self, other);
  452. if (self.p.x < other.p.x) fx = 1.0;
  453. }
  454. fy = 1.0;
  455. if (step.y < 0.0) {
  456. aidy = bumpaabb_overlap_y(self, other);
  457. } else if (step.y > 0.0) {
  458. aidy = bumpaabb_overlap_y(self, other);
  459. fy = -1.0;
  460. } else {
  461. aidy = bumpaabb_overlap_y(self, other);
  462. if (self.p.y < other.p.y) fy = -1.0;
  463. }
  464. if (fabs(aidx) < fabs(aidy)) {
  465. res.x = aidx * fx;
  466. } else if (fabs(aidx) > fabs(aidy)) {
  467. res.y = aidy * fy;
  468. } else {
  469. res.x = aidx * fx;
  470. }
  471. return res;
  472. }
  473. BumpHull * bumphull_free(BumpHull * self) {
  474. bumphull_done(self);
  475. return mem_free(self);
  476. }
  477. /** Returns the flags of the hull, or -1 if the hull is NULL.*/
  478. int bumphull_flags(BumpHull * hull) {
  479. if (!hull) return -1;
  480. return hull->flags;
  481. }
  482. /** Sets the flags of the hull. Returns the flags set or -1 if the hull is NULL
  483. */
  484. int bumphull_flags_(BumpHull * hull, int flags) {
  485. if (!hull) return -1;
  486. return hull->flags = flags;
  487. }
  488. /** Gets an individual flag of the hull. Returns 0 if the hull is NULL.
  489. * Otherwse returns ninzero if the flag is set, and zero if it isn't. */
  490. int bumphull_get_flag(BumpHull * hull, int flag) {
  491. if (!hull) return 0;
  492. return hull->flags & flag;
  493. }
  494. /** Sets an individual flag of the hull. Return 0 if the hull is NULL.
  495. * Otherwse returns nonzero if the flag is set, and zero if it isn't. */
  496. int bumphull_set_flag(BumpHull * hull, int flag) {
  497. if (!hull) return 0;
  498. hull->flags &= flag;
  499. return bumphull_get_flag(hull, flag);
  500. }
  501. /** Unsets an individual flag of the hull. Return 0 if the hull is NULL.
  502. * Otherwse returns nonzero if the flag is set, and zero if it isn't. */
  503. int bumphull_unset_flag(BumpHull * hull, int flag) {
  504. if (!hull) return 0;
  505. hull->flags &= (~flag);
  506. return bumphull_get_flag(hull, flag);
  507. }
  508. /** Returns the group of the hull, or -1 if the hull is NULL.*/
  509. int bumphull_group(BumpHull * hull) {
  510. if (!hull) return -1;
  511. return hull->group;
  512. }
  513. /** Sets the group of the hull. Returns the group set or -1 if the hull
  514. * is NULL */
  515. int bumphull_group_(BumpHull * hull, int group) {
  516. if (!hull) return -1;
  517. return hull->group = group;
  518. }
  519. BumpWorld * bumpworld_alloc() {
  520. return STRUCT_ALLOC(BumpWorld);
  521. }
  522. /* Initializes a world. */
  523. BumpWorld * bumpworld_init(BumpWorld * self) {
  524. if (!self) return NULL;
  525. self->body_max = 0;
  526. self->hull_max = 0;
  527. self->bodies = dynar_newptr(BUMP_WORLD_MAXBODIES);
  528. self->hulls = dynar_newptr(BUMP_WORLD_MAXHULLS);
  529. self->map = NULL;
  530. bumphash_init(&self->hash);
  531. return self;
  532. }
  533. /* Allocates and initializes a world. */
  534. BumpWorld * bumpworld_new(void) {
  535. return bumpworld_init(bumpworld_alloc());
  536. }
  537. /* Cleans up the bump map after use. */
  538. BumpWorld * bumpworld_done(BumpWorld * self) {
  539. if(!self) return NULL;
  540. self->bodies = dynar_free(self->bodies);
  541. self->hulls = dynar_free(self->hulls);
  542. return self;
  543. }
  544. BumpWorld * bumpworld_free(BumpWorld * self) {
  545. if(self) bumpworld_done(self);
  546. return mem_free(self);
  547. }
  548. /** Fetches a body with a given index from the world. */
  549. BumpBody * bumpworld_body(BumpWorld * self, int index) {
  550. return dynar_getptr(self->bodies, index);
  551. }
  552. /** Fetches a hull with a given index from the world. */
  553. BumpHull * bumpworld_hull(BumpWorld * self, int index) {
  554. return dynar_getptr(self->hulls, index);
  555. }
  556. /** Returns the maximum body count for use in loops. */
  557. int bumpworld_body_count(BumpWorld * self) {
  558. return dynar_size(self->bodies);
  559. }
  560. /** Returns the maximum hull count for use in loops. */
  561. int bumpworld_hull_count(BumpWorld * self) {
  562. return dynar_size(self->hulls);
  563. }
  564. /** Adds a body to this world. */
  565. BumpBody * bumpworld_add_body(BumpWorld * self, BumpBody * body) {
  566. int index;
  567. if(!self) return NULL;
  568. if(!body) return NULL;
  569. for (index = 0; index < bumpworld_body_count(self) ; index ++) {
  570. if (!dynar_getptr(self->bodies, index)) {
  571. if(!dynar_putptr(self->bodies, index, body)) return NULL;
  572. body->id = index;
  573. if (index >= self->body_max) self->body_max = index + 1;
  574. return body;
  575. }
  576. }
  577. return NULL;
  578. }
  579. /** Adds a hull to this world. */
  580. BumpHull * bumpworld_add_hull(BumpWorld * self, BumpHull * hull) {
  581. int index;
  582. if(!self) return NULL;
  583. if(!hull) return NULL;
  584. // for (index = 0; index < self
  585. for (index = 0; index < bumpworld_hull_count(self) ; index ++) {
  586. if (!dynar_getptr(self->hulls, index)) {
  587. if(!dynar_putptr(self->hulls, index, hull)) return NULL;
  588. hull->id = index;
  589. if (index >= self->hull_max) self->hull_max = index + 1;
  590. return hull;
  591. }
  592. }
  593. return NULL;
  594. }
  595. /** Removes the hull but does not free it. */
  596. BumpHull * bumpworld_remove_hull(BumpWorld * self, BumpHull * hull) {
  597. if(!self) return NULL;
  598. if(!hull) return NULL;
  599. if (hull->id < 0) return NULL;
  600. dynar_putptr(self->hulls, hull->id, NULL);
  601. hull->id = -1;
  602. self->hull_max--;
  603. return hull;
  604. }
  605. /** Removes the hull and frees it. Returns NULL. */
  606. BumpWorld * bumpworld_delete_hull(BumpWorld * self, BumpHull * hull) {
  607. if(!bumpworld_remove_hull(self, hull)) {
  608. bumphull_free(hull);
  609. }
  610. return self;
  611. }
  612. /** Removes the body but does not free it. */
  613. BumpBody * bumpworld_remove_body_only(BumpWorld * self, BumpBody * body) {
  614. if(!self) return NULL;
  615. if(!body) return NULL;
  616. if (body->id < 0) return NULL;
  617. dynar_putptr(self->bodies, body->id, NULL);
  618. body->id = -1;
  619. return body;
  620. }
  621. /** Removes the body and frees it. Does not remove it's hulls. */
  622. BumpWorld * bumpworld_delete_body_only(BumpWorld * self, BumpBody * body) {
  623. if(!bumpworld_remove_body_only(self, body)) {
  624. bumpbody_free(body);
  625. }
  626. return self;
  627. }
  628. /** Removes the body with the given index and and frees it. Does not
  629. * remove it's hulls. */
  630. BumpWorld * bumpworld_delete_body_only_index(BumpWorld * self, int index) {
  631. BumpBody * body = bumpworld_body(self, index);
  632. return bumpworld_delete_body(self, body);
  633. }
  634. /** Removes the hull with the given index and and frees it. */
  635. BumpWorld * bumpworld_delete_hull_index(BumpWorld * self, int index) {
  636. BumpHull * hull = bumpworld_hull(self, index);
  637. return bumpworld_delete_hull(self, hull);
  638. }
  639. /** Deletes all hulls for the given body. */
  640. BumpWorld * bumpworld_delete_hulls_for(BumpWorld * self, BumpBody * body) {
  641. int hindex;
  642. if (!body) return NULL;
  643. for (hindex = 0; hindex < bumpworld_hull_count(self); hindex++) {
  644. BumpHull * hull = bumpworld_hull(self, hindex);
  645. if (hull && (hull->body == body)) {
  646. bumpworld_delete_hull(self, hull);
  647. }
  648. }
  649. return self;
  650. }
  651. /* Deletes the body and all hulls reated to it. */
  652. BumpWorld * bumpworld_delete_body(BumpWorld * world, BumpBody * body) {
  653. if (!bumpworld_delete_hulls_for(world, body)) return NULL;
  654. return bumpworld_delete_body_only(world, body);
  655. }
  656. /* Deletes the body and all hulls related to it by it's index. */
  657. BumpWorld * bumpworld_delete_body_index(BumpWorld * world, int index) {
  658. BumpBody * body = bumpworld_body(world, index);
  659. return bumpworld_delete_body(world, body);
  660. }
  661. /* Gets the tile map that this world must use to check collisions.
  662. * Bumpworld doesn't own the map, and won't clean it up on bumpworld_free.
  663. */
  664. Tilemap * bumpworld_tilemap(BumpWorld * self) {
  665. if(!self) return NULL;
  666. return self->map;
  667. }
  668. /* Sets the tile map that this world must use to check collisions.
  669. * Does not clean up the tile map since bumpworld doesn't own the map.
  670. */
  671. void * bumpworld_tilemap_(BumpWorld * self, void * map) {
  672. if(!self) return NULL;
  673. self->map = map;
  674. return map;
  675. }
  676. /* Calculates the motion and speed of the body
  677. disregarding any collisions. v_next and p_next will be set, but p and v not.
  678. Call bumpbody_update_commit after collision calculation to finalize the motion. */
  679. void bumpbody_integrate(BumpBody * self, double dt) {
  680. if (!self) return;
  681. /*
  682. self->a_next = bevec_add(self->a, bevec_div(self->f, self->m));
  683. self->v_next = bevec_add(self->v, bevec_mul(self->a_next, dt));
  684. */
  685. self->v_next = self->v;
  686. self->p_next = bevec_add(self->p, bevec_mul(self->v_next, dt));
  687. }
  688. /* Uses the values in p_next and v_next current position and value. */
  689. void bumpbody_commit(BumpBody * self) {
  690. if (!self) return;
  691. self->v = self->v_next;
  692. self->p = self->p_next;
  693. }
  694. /* Collides a hull with a single tile in the tile map. *
  695. */
  696. void
  697. bumpworld_collide_hull_tile
  698. (BumpWorld * self, BumpHull * hull, BumpAABB * bounds,
  699. int x, int y, int z, double dt) {
  700. Thing * thing = NULL;
  701. int tx, ty;
  702. tx = (x / TILE_W);
  703. ty = (y / TILE_H);
  704. // Remember, z goes first since it's a layer.
  705. Tile * tile = tilemap_get(self->map, z, tx, ty);
  706. // No tile, no collision, sorry.
  707. if (!tile) return;
  708. double tcx = TILE_W * tx + TILE_W / 2;
  709. double tcy = TILE_H * ty + TILE_H / 2;
  710. BumpAABB tileaabb = bumpaabb(tcx, tcy, TILE_W, TILE_H);
  711. // No overlap, no collision, sorry. ;)
  712. if(!bumpaabb_overlap_p((*bounds), tileaabb)) {
  713. return;
  714. }
  715. if((hull) && (hull->body)) {
  716. thing = bumphull_body_data(hull);
  717. }
  718. if ( thing && (thing_z(thing) > 1) && (z == 2) ) {
  719. /* There tile is in the second-to upper layer, so if the hull is there, it is supported. */
  720. bumphull_support_(hull, TRUE);
  721. }
  722. /* Tile in non-colliding layer. Ignore collision. */
  723. if ((hull->layers & (1 << (z))) != (1 << (z))) {
  724. return;
  725. }
  726. // Check if the point collides with a wall
  727. if (tile_isflag(tile, TILE_WALL)) {
  728. // Calculate the pushback vector.
  729. BeVec push =
  730. bumpaabb_collision_pushback((*bounds), tileaabb, hull->body->v, dt);
  731. /* Add the pushback to the next motion of this hull's body */
  732. hull->body->p_next = bevec_add(hull->body->p_next, push);
  733. bounds->p = hull->body->p_next;
  734. hull->body->locks = hull->body->locks | bevec_lock_flags(push);
  735. } else if (tile_isflag(tile, TILE_STAIR) && thing) {
  736. /* Up to the upper level if stair is touched. */
  737. thing_z_(thing, 3);
  738. /* Give it a "support" boost so it doesn't drop down right away. */
  739. bumphull_support_(hull, TRUE);
  740. }
  741. }
  742. /* Calculates the displacement vector that is needed to push back
  743. * to_push out of pushed. Pvec is the motion vector of the collision motion.
  744. * It is used to push out the hull.
  745. */
  746. void bumpworld_collide_hull_tilemap(BumpWorld * self, BumpHull * hull, double dt) {
  747. /* Collide the hull with the grid, setting lock flags to disallow further motion
  748. in the direction. For now, no swept collisions are supported, and
  749. the tile map is purely rectilinear (no diagonals yet).
  750. The tilemap tiles that could overlap with the outline of the hull have to be
  751. checked for collision at the future location of this hull;
  752. */
  753. BumpAABB bounds;
  754. int x, y, z;
  755. if ((!hull) || (!hull->body)) return;
  756. if (!self->map) return;
  757. /* Get bounds of hull, these will be changed. */
  758. bounds = bumphull_aabb_next(hull);
  759. /* Reset hull support to false. */
  760. bumphull_support_(hull, FALSE);
  761. for (y = bumpaabb_top(&bounds); y <= (bumpaabb_down(&bounds) + 1) ; y += (TILE_H ) ) {
  762. for (x = bumpaabb_left(&bounds); x <= (bumpaabb_right(&bounds) + 1) ; x += (TILE_W / 2 )) {
  763. for (z = 0; z < tilemap_panes(self->map) ; z++) {
  764. bumpworld_collide_hull_tile(self, hull, &bounds, x, y, z, dt);
  765. }
  766. }
  767. }
  768. }
  769. /* Perform one round of hull-to-hull collisions. */
  770. void
  771. bumpworld_collide_hulls
  772. (BumpWorld * self, int round, BumpHull * hull1, BumpHull * hull2, double dt) {
  773. static int serno = 0;
  774. BeVec push, push1, push2, vrel;
  775. BumpAABB bounds1;
  776. BumpAABB bounds2;
  777. int x, y, z, tx, ty, g1, g2;
  778. if ((!hull1) || (!hull1->body)) return;
  779. if ((!hull2) || (!hull2->body)) return;
  780. /* Group check: hulls in the same strictly positive group do not collide. */
  781. g1 = hull1->group;
  782. g2 = hull2->group;
  783. if ( (g1 > 0) && (g2 > 0) && (g1 == g2) ) {
  784. return;
  785. }
  786. (void) self;
  787. serno++;
  788. bounds1 = bumphull_aabb_next(hull1);
  789. bounds2 = bumphull_aabb_next(hull2);
  790. /* No overlap, no collision. */
  791. if (!bumpaabb_overlap_p(bounds1, bounds2)) {
  792. return;
  793. }
  794. /* Sensors don't detect each other. */
  795. if (hull1->flags & BUMP_FLAG_SENSOR) {
  796. if (hull2->flags & BUMP_FLAG_SENSOR) {
  797. return;
  798. }
  799. }
  800. /* Allow the script to break off a beginning collision. */
  801. if ((round == 0)
  802. && (!callrb_collide_hulls(hull1, hull2, COLLIDE_BEGIN, NULL))) {
  803. return;
  804. }
  805. vrel = bevec_sub(hull1->body->v, hull2->body->v);
  806. push =
  807. bumpaabb_collision_pushback(bounds1, bounds2, vrel, dt);
  808. /* This 0.5 should be related to the body's mass or something. */
  809. push1 = bevec_mul(push, 0.5);
  810. push2 = bevec_mul(push, -0.5);
  811. if (round == 0) {
  812. hull1->body->locks = 0;
  813. hull2->body->locks = 0;
  814. } else {
  815. push1 = bevec_lock(push1, hull1->body->locks);
  816. push2 = bevec_lock(push2, hull2->body->locks);
  817. }
  818. /* Sensors cause no displacement. */
  819. if ((!(hull1->flags & BUMP_FLAG_SENSOR)) &&
  820. (!(hull2->flags & BUMP_FLAG_SENSOR))
  821. )
  822. {
  823. hull1->body->p_next = bevec_add(hull1->body->p_next, push1);
  824. hull2->body->p_next = bevec_add(hull2->body->p_next, push2);
  825. hull1->body->v = bevec_add(hull1->body->v, bevec_mul(push1, dt));
  826. hull2->body->v = bevec_add(hull2->body->v, bevec_mul(push2, dt));
  827. }
  828. if (round == 1) {
  829. /* Signal the script that the collision is ongoing or ending. */
  830. int colltype = COLLIDE_COLLIDING;
  831. bounds1 = bumphull_aabb_next(hull1);
  832. bounds2 = bumphull_aabb_next(hull2);
  833. if(!bumpaabb_overlap_p(bounds1, bounds2)) {
  834. colltype = COLLIDE_END;
  835. }
  836. callrb_collide_hulls(hull1, hull2, colltype, NULL);
  837. }
  838. }
  839. /**
  840. * Adds a hull to a spatial hash. Not currently used.
  841. * since current collision detection still seems fast enough.
  842. * Perhaps add as an optimization to support really a lot of
  843. * hulls later.
  844. */
  845. void bumphash_addhull(BumpHash * hash, BumpHull * hull) {
  846. int x, y;
  847. BumpAABB bounds = bumphull_aabb_real(hull);
  848. for (y = bumpaabb_top(&bounds); y <= bumpaabb_down(&bounds) ; y += BUMPHASH_TILE_H) {
  849. for (x = bumpaabb_left(&bounds); x <= bumpaabb_right(&bounds) ; x += BUMPHASH_TILE_W) {
  850. bumphash_add(hash, x, y, hull);
  851. }
  852. }
  853. }
  854. /* Commit motions. */
  855. BumpWorld * bumpworld_commit(BumpWorld * self) {
  856. int index;
  857. /* Commit motions. */
  858. for (index = 0; index < self->body_max; index ++) {
  859. BumpBody * body = dynar_getptr(self->bodies, index);
  860. bumpbody_commit(body);
  861. }
  862. return self;
  863. }
  864. #undef BUMPWORLD_COMMIT_AFTER_DEBUG
  865. /* Makes unsupported hulls fall down from upper to lower level. */
  866. BumpWorld * bumpworld_hulls_fall_down(BumpWorld * self, double dt) {
  867. int index, jndex;
  868. /* simple integration for now. */
  869. for (index = 0; index < self->body_max; index ++) {
  870. BumpBody * body = dynar_getptr(self->bodies, index);
  871. bumpbody_integrate(body, dt);
  872. }
  873. return self;
  874. }
  875. BumpWorld * bumpworld_update(BumpWorld * self, double dt) {
  876. int index, jndex;
  877. /* simple integration for now. */
  878. for (index = 0; index < self->body_max; index ++) {
  879. BumpBody * body = dynar_getptr(self->bodies, index);
  880. bumpbody_integrate(body, dt);
  881. }
  882. /* XXX: Update the spatial hash.
  883. bumphash_empty(&self->hash);
  884. for (index = 0; index < self->hull_max; index ++) {
  885. BumpHull * hull = dynar_getptr(self->hulls, index);
  886. bumphash_addhull(&self->hash, hull);
  887. }
  888. */
  889. /* First round of hull to hull collisions. */
  890. for (index = 0; index < self->hull_max; index ++) {
  891. BumpHull * hull1 = bumpworld_hull(self, index);
  892. if (!hull1) continue;
  893. if (hull1->flags & BUMP_FLAG_DISABLED) continue;
  894. /* Todo: broad phase checking. */
  895. for (jndex = index + 1 ; jndex < self->hull_max; jndex++ ) {
  896. BumpHull * hull2 = bumpworld_hull(self, index);
  897. if (!hull2) continue;
  898. if (hull2->flags & BUMP_FLAG_DISABLED) continue;
  899. bumpworld_collide_hulls(self, 0, hull1, hull2, dt);
  900. }
  901. }
  902. /* Hull to tile map collisions, if needed. */
  903. if (self->map) {
  904. for (index = 0; index < self->hull_max; index ++) {
  905. BumpHull * hull = dynar_getptr(self->hulls, index);
  906. if (!hull) continue;
  907. if (hull->flags & BUMP_FLAG_DISABLED) continue;
  908. bumpworld_collide_hull_tilemap(self, hull, dt);
  909. }
  910. }
  911. /* Resolve the hull to hull collisions, taking the lock set by the grid
  912. * into consideration.
  913. */
  914. for (index = 0; index < self->hull_max; index ++) {
  915. BumpHull * hull1 = dynar_getptr(self->hulls, index);
  916. if (!hull1) continue;
  917. if (hull1->flags & BUMP_FLAG_DISABLED) continue;
  918. /* Todo: broad phase checking. */
  919. for (jndex = index + 1 ; jndex < self->hull_max; jndex++ ) {
  920. BumpHull * hull2 = dynar_getptr(self->hulls, jndex);
  921. if (!hull2) continue;
  922. if (hull2->flags & BUMP_FLAG_DISABLED) continue;
  923. bumpworld_collide_hulls(self, 1, hull1, hull2, dt);
  924. }
  925. }
  926. /* Make hulls (things) fall down from the upper levels if
  927. * not supported by a tile on tile map level 3 or 4.
  928. * (implement flying later)
  929. */
  930. // bumpworld_hulls_fall_down(self, dt);
  931. /* Commit motions if not showing debug drawing. */
  932. #ifndef BUMPWORLD_COMMIT_AFTER_DEBUG
  933. bumpworld_commit(self);
  934. #endif
  935. return self;
  936. }
  937. static void bumpaabb_draw(BumpAABB * bounds, Color color, int thickness, Camera * camera) {
  938. int cx ;
  939. int cy ;
  940. int drawx, x, w;
  941. int drawy, y, h;
  942. cx = camera_at_x(camera);
  943. cy = camera_at_y(camera);
  944. w = bounds->hs.x * 2;
  945. h = bounds->hs.y * 2;
  946. x = bounds->p.x - bounds->hs.x;
  947. y = bounds->p.y - bounds->hs.y;
  948. drawx = x - cx;
  949. drawy = y - cy;
  950. draw_box(drawx, drawy, w, h, color, thickness);
  951. }
  952. static void bumpworld_draw_tilemap_debug(BumpTilemap * self, Camera * camera) {
  953. (void) self; (void) camera;
  954. }
  955. static void bumphull_draw_debug(BumpWorld * world, BumpHull * self, Camera * camera) {
  956. int cx ;
  957. int cy ;
  958. int drawx, x;
  959. int drawy, y;
  960. double drawx1, drawy1, drawx2, drawy2;
  961. int w, h ;
  962. int t = 2;
  963. BeVec next_p;
  964. BumpAABB bounds;
  965. Color color;
  966. // don't draw null things.
  967. if(!self) return;
  968. cx = camera_at_x(camera);
  969. cy = camera_at_y(camera);
  970. bounds = bumphull_aabb_real(self);
  971. w = bounds.hs.x * 2;
  972. h = bounds.hs.y * 2;
  973. color = color_rgba(0, 0, 64, 255);
  974. {
  975. x = bounds.p.x;
  976. y = bounds.p.y;
  977. t = 2;
  978. }
  979. /* Do not draw out of camera range. */
  980. if(!camera_cansee(camera, x, y, w, h)) {
  981. return;
  982. }
  983. drawx = x - cx;
  984. drawy = y - cy;
  985. bumpaabb_draw(&bounds, color, t, camera);
  986. next_p = /*bevec_add( */ self->body->p_next /* , self->delta) */ ;
  987. bounds.p = next_p;
  988. drawy1 = bumpaabb_top(&bounds) - (double)cy;
  989. drawy2 = bumpaabb_down(&bounds) - (double)cy;
  990. drawx1 = bumpaabb_left(&bounds) - (double)cx;
  991. drawx2 = bumpaabb_right(&bounds) - (double)cx;
  992. color = color_rgba(64, 0, 128, 128);
  993. // al_draw_rectangle(floor(drawx1), floor(drawy1), floor(drawx2), floor(drawy2), color, 1);
  994. bumpaabb_draw(&bounds, color, 1, camera);
  995. color = color_rgba(255, 0, 64, 128);
  996. for (y = bumpaabb_top(&bounds); y <= (bumpaabb_down(&bounds) + 1) ; y += (TILE_H) ) {
  997. for (x = bumpaabb_left(&bounds); x <= (bumpaabb_right(&bounds) + 1) ; x += (TILE_W)) {
  998. int tx = (x / TILE_W);
  999. int ty = (y / TILE_H);
  1000. Tile * tile = tilemap_get(world->map, 1, tx, ty);
  1001. // Check if the point collides with a wall...
  1002. if (tile_isflag(tile, TILE_WALL)) {
  1003. BeVec ovec;
  1004. double tcx = TILE_W * tx + TILE_W / 2;
  1005. double tcy = TILE_H * ty + TILE_H / 2;
  1006. BumpAABB tileaabb = bumpaabb(tcx, tcy, TILE_W, TILE_H);
  1007. color = color_rgba(255, 128, 128, 128);
  1008. bumpaabb_draw(&tileaabb, color, 1, camera);
  1009. drawx = (tx * TILE_W) - cx;
  1010. drawy = (ty * TILE_H) - cy;
  1011. color = color_rgba(255, 0, 64, 128);
  1012. draw_box(drawx, drawy, TILE_W, TILE_H, color, 1);
  1013. ovec = bumpaabb_overlap_vector(bounds, tileaabb);
  1014. color = color_rgba(64, 0, 255, 128);
  1015. al_draw_line(drawx, drawy, drawx + ovec.x, drawy + ovec.y, color, 1);
  1016. al_draw_circle(drawx + ovec.x, drawy + ovec.y, 3, color, 1);
  1017. }
  1018. drawx = x - cx;
  1019. drawy = y - cy;
  1020. // al_draw_filled_circle(drawx, drawy, 3, color);
  1021. }
  1022. }
  1023. }
  1024. static void bumpbody_draw_debug(BumpBody * self, Camera * camera) {
  1025. int cx ;
  1026. int cy ;
  1027. int drawx, x;
  1028. int drawy, y;
  1029. int w, h ;
  1030. int t = 2;
  1031. Color color;
  1032. // don't draw null things.
  1033. if(!self) return;
  1034. cx = camera_at_x(camera);
  1035. cy = camera_at_y(camera);
  1036. w = 32;
  1037. h = 32;
  1038. color = color_rgba(128, 255, 255, 128);
  1039. {
  1040. x = self->p.x;
  1041. y = self->p.y;
  1042. t = 1;
  1043. }
  1044. /* Do not draw out of camera range. */
  1045. if(!camera_cansee(camera, x, y, w, h)) {
  1046. return;
  1047. }
  1048. drawx = x - cx;
  1049. drawy = y - cy;
  1050. draw_box(drawx - (w / 2), drawy - (h / 2), w, h, color, t);
  1051. color = color_rgba(128, 16, 16, 128);
  1052. al_draw_line(drawx, drawy, drawx + self->v.x, drawy + self->v.y, color, 1);
  1053. al_draw_filled_circle(self->p_next.x - cx, self->p_next.y - cy, 3, color);
  1054. }
  1055. BumpWorld * bumpworld_draw_debug(BumpWorld * self) {
  1056. int index;
  1057. State * state = state_get();
  1058. Camera * camera = state_camera(state);
  1059. for (index = 0 ; index < self->hull_max; index ++) {
  1060. BumpHull * hull = dynar_getptr(self->hulls, index);
  1061. bumphull_draw_debug(self, hull, camera);
  1062. }
  1063. for (index = 0 ; index < self->body_max; index ++) {
  1064. BumpBody * body = dynar_getptr(self->bodies, index);
  1065. bumpbody_draw_debug(body, camera);
  1066. }
  1067. /* Commit motions if showing debug drawing. */
  1068. #ifdef BUMPWORLD_COMMIT_AFTER_DEBUG
  1069. bumpworld_commit(self);
  1070. #endif
  1071. return NULL;
  1072. }
  1073. /** Finds all hulls in a given rectangle and stores
  1074. * up to max_hulls of them in the array hulls.
  1075. * Returns the amount of hulls found or negative on error. */
  1076. int bumpworld_find_and_fetch_hulls(BumpWorld * self, BumpAABB search,
  1077. BumpHull ** hulls, int max_hulls) {
  1078. int amount = 0;
  1079. int index;
  1080. int stop = self->hull_max;
  1081. if (stop > max_hulls) stop = max_hulls;
  1082. if (!hulls) return -1;
  1083. for (index = 0; index < stop; index ++) {
  1084. BumpHull * hull = dynar_getptr(self->hulls, index);
  1085. BumpAABB hullaabb;
  1086. if (!hull) continue;
  1087. hullaabb = bumphull_aabb_real(hull);
  1088. if (bumpaabb_overlap_p(hullaabb, search)) {
  1089. hulls[amount] = hull;
  1090. amount ++;
  1091. }
  1092. }
  1093. return amount;
  1094. }
  1095. /** Finds all hulls in a given rectangle and calls the callback for each of them.
  1096. * Returns 0. If the callback returns nonzero returns this in stead immediately
  1097. * and stop calling the callback. */
  1098. int bumpworld_find_hulls(BumpWorld * self, BumpAABB search, void * extra,
  1099. int (*callback)(BumpHull * hull, void * extra)) {
  1100. int amount = 0;
  1101. int index;
  1102. LOG("Find hull: %d hulls known.\n", self->hull_max);
  1103. for (index = 0; index < self->hull_max; index ++) {
  1104. BumpHull * hull = dynar_getptr(self->hulls, index);
  1105. BumpAABB hullaabb;
  1106. if (!hull) continue;
  1107. hullaabb = bumphull_aabb_real(hull);
  1108. if (bumpaabb_overlap_p(hullaabb, search)) {
  1109. int res = callback(hull, extra);
  1110. if (res) return res;
  1111. } else {
  1112. }
  1113. }
  1114. return 0;
  1115. }
  1116. /** Finds all hulls that are conected to body and stores
  1117. * up to max_hulls of them in the array hulls.
  1118. * Returns the amount of hulls found or negative on error. */
  1119. int bumpworld_fetch_body_hulls(BumpWorld * self, BumpBody * body,
  1120. BumpHull ** hulls, int max_hulls) {
  1121. int amount = 0;
  1122. int index;
  1123. int stop = self->hull_max;
  1124. if (stop > max_hulls) stop = max_hulls;
  1125. if (!hulls) return -1;
  1126. for (index = 0; index < stop; index ++) {
  1127. BumpHull * hull = dynar_getptr(self->hulls, index);
  1128. if (!hull) continue;
  1129. if (hull->body == body) {
  1130. hulls[amount] = hull;
  1131. amount ++;
  1132. }
  1133. }
  1134. return amount;
  1135. }
  1136. /** Finds all hulls for the given body and calls the callback for each of them.
  1137. * Returns 0. If the callback returns nonzero, returns this in stead immediately
  1138. * and stop calling the callback. */
  1139. int bumpworld_find_body_hulls(BumpWorld * self, BumpBody * body, void * extra,
  1140. int (*callback)(BumpHull * hull, void * extra)) {
  1141. int amount = 0;
  1142. int index;
  1143. LOG("Find hull: %d hulls known.\n", self->hull_max);
  1144. for (index = 0; index < self->hull_max; index ++) {
  1145. BumpHull * hull = dynar_getptr(self->hulls, index);
  1146. if (!hull) continue;
  1147. if (hull->body == body) {
  1148. int res = callback(hull, extra);
  1149. if (res) return res;
  1150. }
  1151. }
  1152. return 0;
  1153. }
  1154. /** Adds a new hull attached to the given body into the physical world. */
  1155. BumpHull *
  1156. bumpworld_new_hull(BumpWorld * self, BumpBody * body, BeVec delta, BumpAABB bounds, int layers, int kind) {
  1157. BumpHull * hull = bumphull_newall(body, delta, bounds, layers, kind);
  1158. return bumpworld_add_hull(self, hull);
  1159. }
  1160. /** Sets a flag on the hull indicated by index. */
  1161. int bumpworld_set_hull_flag(BumpWorld * me, int index, int flag) {
  1162. if (!me) return 0;
  1163. return bumphull_set_flag(bumpworld_hull(me, index), flag);
  1164. }
  1165. /** Unsets a flag for the hull indicated by index. */
  1166. int bumpworld_unset_hull_flag(BumpWorld * me, int index, int flag) {
  1167. if (!me) return 0;
  1168. return bumphull_unset_flag(bumpworld_hull(me, index), flag);
  1169. }
  1170. /** Sets all flags for the hull indicated by index. */
  1171. int bumpworld_hull_flags_(BumpWorld * me, int index, int flags) {
  1172. if (!me) return 0;
  1173. return bumphull_flags_(bumpworld_hull(me, index), flags);
  1174. }
  1175. /** Gets all flags for the hull indicated by index. */
  1176. int bumpworld_hull_flags(BumpWorld * me, int index) {
  1177. if (!me) return 0;
  1178. return bumphull_flags(bumpworld_hull(me, index));
  1179. }