asim.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #include "asim.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <math.h>
  6. #define GRAVITY -9.81f
  7. #define TIME_STEP (1.0 / 60.0)
  8. #define MAX_BVH_DEPTH 20
  9. typedef struct {
  10. vec4_t min;
  11. vec4_t max;
  12. } aabb_t;
  13. typedef struct {
  14. vec4_t position;
  15. vec4_t velocity;
  16. float radius;
  17. float mass;
  18. } sphere_t;
  19. typedef struct {
  20. vec4_t v0;
  21. vec4_t v1;
  22. vec4_t v2;
  23. vec4_t normal;
  24. aabb_t bounds;
  25. } triangle_t;
  26. typedef struct bvh_node {
  27. aabb_t bounds;
  28. struct bvh_node *left, *right;
  29. triangle_t *triangles;
  30. int num_tris;
  31. int is_leaf;
  32. } bvh_node_t;
  33. typedef struct {
  34. bvh_node_t *root;
  35. } mesh_t;
  36. sphere_t sphere = {
  37. .position = {0, 0, 0},
  38. .velocity = {0, 0, 0},
  39. // .radius = 1.0f,
  40. .radius = 0.2f,
  41. .mass = 1.0f
  42. };
  43. mesh_t mesh;
  44. aabb_t root_bounds = {
  45. {-10, -10, -10},
  46. {10, 10, 10}
  47. };
  48. physics_pair_t ppair;
  49. static inline aabb_t merge_aabbs(aabb_t a, aabb_t b) {
  50. return (aabb_t){
  51. .min = {fminf(a.min.x, b.min.x), fminf(a.min.y, b.min.y), fminf(a.min.z, b.min.z)},
  52. .max = {fmaxf(a.max.x, b.max.x), fmaxf(a.max.y, b.max.y), fmaxf(a.max.z, b.max.z)}
  53. };
  54. }
  55. static inline int sphere_aabb_intersect(sphere_t *s, aabb_t *a) {
  56. float x = fmaxf(a->min.x, fminf(s->position.x, a->max.x));
  57. float y = fmaxf(a->min.y, fminf(s->position.y, a->max.y));
  58. float z = fmaxf(a->min.z, fminf(s->position.z, a->max.z));
  59. float dx = x - s->position.x, dy = y - s->position.y, dz = z - s->position.z;
  60. return dx * dx + dy * dy + dz * dz <= s->radius * s->radius;
  61. }
  62. // Comparison function for sorting triangles by x-coordinate of centroid
  63. static int compare_triangles(const void *a, const void *b) {
  64. triangle_t *ta = (triangle_t *)a;
  65. triangle_t *tb = (triangle_t *)b;
  66. vec4_t ca = vec4_mult(vec4_add(vec4_add(ta->v0, ta->v1), ta->v2), 1.0f / 3.0f);
  67. vec4_t cb = vec4_mult(vec4_add(vec4_add(tb->v0, tb->v1), tb->v2), 1.0f / 3.0f);
  68. return (ca.x > cb.x) - (ca.x < cb.x);
  69. }
  70. static bvh_node_t *create_bvh_node(triangle_t *tris, int num_tris, int depth) {
  71. bvh_node_t *node = (bvh_node_t *)malloc(sizeof(bvh_node_t));
  72. *node = (bvh_node_t){
  73. .left = NULL,
  74. .right = NULL,
  75. .triangles = NULL,
  76. .num_tris = 0,
  77. .is_leaf = 1
  78. };
  79. if (num_tris <= 1 || depth >= MAX_BVH_DEPTH) {
  80. node->num_tris = num_tris;
  81. if (num_tris) {
  82. node->triangles = (triangle_t *)malloc(num_tris * sizeof(triangle_t));
  83. memcpy(node->triangles, tris, num_tris * sizeof(triangle_t));
  84. node->bounds = tris[0].bounds;
  85. }
  86. else {
  87. node->bounds = root_bounds;
  88. }
  89. return node;
  90. }
  91. qsort(tris, num_tris, sizeof(triangle_t), compare_triangles);
  92. int mid = num_tris / 2;
  93. node->is_leaf = 0;
  94. node->left = create_bvh_node(tris, mid, depth + 1);
  95. node->right = create_bvh_node(tris + mid, num_tris - mid, depth + 1);
  96. node->bounds = merge_aabbs(node->left->bounds, node->right->bounds);
  97. return node;
  98. }
  99. static void collide_sphere_triangle(sphere_t *s, triangle_t *t) {
  100. if (!sphere_aabb_intersect(s, &t->bounds)) {
  101. return;
  102. }
  103. vec4_t to_sphere = vec4_sub(s->position, t->v0);
  104. float dist = vec4_dot(to_sphere, t->normal);
  105. if (fabsf(dist) > s->radius) {
  106. return;
  107. }
  108. vec4_t p = vec4_sub(s->position, vec4_mult(t->normal, dist));
  109. vec4_t e0 = vec4_sub(t->v1, t->v0), e1 = vec4_sub(t->v2, t->v1), e2 = vec4_sub(t->v0, t->v2);
  110. vec4_t c0 = vec4_sub(p, t->v0), c1 = vec4_sub(p, t->v1), c2 = vec4_sub(p, t->v2);
  111. if (vec4_dot(t->normal, vec4_cross(e0, c0)) >= 0 &&
  112. vec4_dot(t->normal, vec4_cross(e1, c1)) >= 0 &&
  113. vec4_dot(t->normal, vec4_cross(e2, c2)) >= 0) {
  114. float penetration = s->radius - dist;
  115. if (dist < 0) {
  116. penetration = -penetration;
  117. }
  118. s->position = vec4_add(s->position, vec4_mult(t->normal, penetration));
  119. float v_dot_n = vec4_dot(s->velocity, t->normal);
  120. vec4_t n_vel = vec4_mult(t->normal, v_dot_n);
  121. s->velocity = vec4_add(vec4_sub(s->velocity, n_vel), vec4_mult(n_vel, -0.01f));
  122. vec4_t contact_point = vec4_sub(s->position, vec4_mult(t->normal, s->radius));
  123. ppair.pos_a_x = contact_point.x;
  124. ppair.pos_a_y = contact_point.y;
  125. ppair.pos_a_z = contact_point.z;
  126. }
  127. }
  128. static void query_bvh(sphere_t *s, bvh_node_t *n) {
  129. if (!n || !sphere_aabb_intersect(s, &n->bounds)) {
  130. return;
  131. }
  132. if (n->is_leaf) {
  133. for (int i = 0; i < n->num_tris; i++) {
  134. collide_sphere_triangle(s, &n->triangles[i]);
  135. }
  136. }
  137. else {
  138. query_bvh(s, n->left);
  139. query_bvh(s, n->right);
  140. }
  141. }
  142. static void free_bvh(bvh_node_t *n) {
  143. if (!n) {
  144. return;
  145. }
  146. if (n->is_leaf) {
  147. free(n->triangles);
  148. }
  149. else {
  150. free_bvh(n->left);
  151. free_bvh(n->right);
  152. }
  153. free(n);
  154. }
  155. void asim_world_create() {
  156. }
  157. void asim_world_destroy() {
  158. free_bvh(mesh.root);
  159. mesh.root = NULL;
  160. }
  161. void asim_world_update() {
  162. ppair.pos_a_x = 0;
  163. ppair.pos_a_y = 0;
  164. ppair.pos_a_z = 0;
  165. const int sub_steps = 2;
  166. float dt = TIME_STEP / sub_steps;
  167. for (int i = 0; i < sub_steps; i++) {
  168. sphere.velocity.z += GRAVITY * dt;
  169. sphere.position = vec4_add(sphere.position, vec4_mult(sphere.velocity, dt));
  170. query_bvh(&sphere, mesh.root);
  171. }
  172. }
  173. physics_pair_t *asim_world_get_contact() {
  174. return &ppair;
  175. }
  176. void *asim_body_create(int shape, float mass, float dimx, float dimy, float dimz, float x, float y, float z, void *posa, void *inda, float scale_pos) {
  177. if (shape == 1) { // SPHERE
  178. sphere.position.x = x;
  179. sphere.position.y = y;
  180. sphere.position.z = z;
  181. sphere.velocity.x = 0;
  182. sphere.velocity.y = 0;
  183. sphere.velocity.z = 0;
  184. return NULL;
  185. }
  186. i16_array_t *pa = posa;
  187. u32_array_t *ia = inda;
  188. int num_tris = ia->length / 3;
  189. triangle_t *tris = (triangle_t *)malloc(num_tris * sizeof(triangle_t));
  190. float scale = (1.0 / 32767.0) * scale_pos;
  191. for (int i = 0; i < num_tris; i++) {
  192. tris[i].v0 = (vec4_t){pa->buffer[ia->buffer[i * 3 ] * 4 ] * scale,
  193. pa->buffer[ia->buffer[i * 3 ] * 4 + 1] * scale,
  194. pa->buffer[ia->buffer[i * 3 ] * 4 + 2] * scale};
  195. tris[i].v1 = (vec4_t){pa->buffer[ia->buffer[i * 3 + 1] * 4 ] * scale,
  196. pa->buffer[ia->buffer[i * 3 + 1] * 4 + 1] * scale,
  197. pa->buffer[ia->buffer[i * 3 + 1] * 4 + 2] * scale};
  198. tris[i].v2 = (vec4_t){pa->buffer[ia->buffer[i * 3 + 2] * 4 ] * scale,
  199. pa->buffer[ia->buffer[i * 3 + 2] * 4 + 1] * scale,
  200. pa->buffer[ia->buffer[i * 3 + 2] * 4 + 2] * scale};
  201. vec4_t edge1 = vec4_sub(tris[i].v1, tris[i].v0);
  202. vec4_t edge2 = vec4_sub(tris[i].v2, tris[i].v0);
  203. tris[i].normal = vec4_mult(vec4_cross(edge1, edge2), 1.0f / vec4_len(vec4_cross(edge1, edge2)));
  204. tris[i].bounds = (aabb_t){
  205. .min = {fminf(fminf(tris[i].v0.x, tris[i].v1.x), tris[i].v2.x),
  206. fminf(fminf(tris[i].v0.y, tris[i].v1.y), tris[i].v2.y),
  207. fminf(fminf(tris[i].v0.z, tris[i].v1.z), tris[i].v2.z)},
  208. .max = {fmaxf(fmaxf(tris[i].v0.x, tris[i].v1.x), tris[i].v2.x),
  209. fmaxf(fmaxf(tris[i].v0.y, tris[i].v1.y), tris[i].v2.y),
  210. fmaxf(fmaxf(tris[i].v0.z, tris[i].v1.z), tris[i].v2.z)}
  211. };
  212. }
  213. mesh.root = create_bvh_node(tris, num_tris, 0);
  214. free(tris);
  215. return NULL;
  216. }
  217. void asim_body_apply_impulse(void *body, float x, float y, float z) {
  218. sphere.velocity.x += x;
  219. sphere.velocity.y += y;
  220. sphere.velocity.z += z;
  221. }
  222. void asim_body_get_pos(void *body, vec4_t *pos) {
  223. pos->x = sphere.position.x;
  224. pos->y = sphere.position.y;
  225. pos->z = sphere.position.z;
  226. }
  227. void asim_body_get_rot(void *body, quat_t *rot) {
  228. }
  229. void asim_body_sync_transform(void *body, vec4_t pos, quat_t rot) {
  230. sphere.position.x = pos.x;
  231. sphere.position.y = pos.y;
  232. sphere.position.z = pos.z;
  233. }
  234. void asim_body_remove(void *body) {
  235. }