13 /*---------------------------------------------------------------------------*/
15 static dWorldID world;
16 static dSpaceID space;
17 static dJointGroupID group;
21 static dBodyID *bodies;
22 static dBodyID *balls;
24 /*---------------------------------------------------------------------------*/
27 * Polygons in the same order as planes, one polygon per plane, each
28 * starting with the number of vertices, followed by the vertex
29 * indices in counter-clockwise order.
41 static void make_convex(struct convex *cx, struct s_file *fp, struct s_lump *lp)
46 * A debug build of ODE (0.11.1 as I write this) will print a
47 * bunch of warnings about our planes not containing the origin
48 * and vertices having the wrong winding. The latter is triggered
49 * by presuming that the former shall be fulfilled, but the former
50 * basically doesn't matter; collision detection handles
51 * origin-facing planes just fine, provided the vertices on the
52 * plane are still counter-clockwise wrt the plane normal.
55 memset(cx, 0, sizeof (*cx));
57 if ((cx->planes = malloc(sizeof (dReal) * 4 * lp->sc)))
59 for (i = 0; i < lp->sc; i++)
61 struct s_side *sp = fp->sv + fp->iv[lp->s0 + i];
63 cx->planes[i * 4 + 0] = sp->n[0];
64 cx->planes[i * 4 + 1] = sp->n[1];
65 cx->planes[i * 4 + 2] = sp->n[2];
66 cx->planes[i * 4 + 3] = sp->d;
72 if ((cx->points = malloc(sizeof (dReal) * 3 * lp->vc)))
74 for (i = 0; i < lp->vc; i++)
76 struct s_vert *vp = fp->vv + fp->iv[lp->v0 + i];
78 cx->points[i * 3 + 0] = vp->p[0];
79 cx->points[i * 3 + 1] = vp->p[1];
80 cx->points[i * 3 + 2] = vp->p[2];
86 if ((cx->polygons = malloc(sizeof (unsigned) * lp->fc)))
87 for (i = 0; i < lp->fc; i++)
88 cx->polygons[i] = fp->iv[lp->f0 + i];
91 void free_convex(struct convex *cx)
98 /*---------------------------------------------------------------------------*/
100 #define CAT_OBJECT 0x1
101 #define CAT_WORLD 0x2
103 static void build_node(dBodyID body, dSpaceID parent,
107 dSpaceID node = dHashSpaceCreate(parent);
111 for (i = 0; i < np->lc; i++)
113 struct s_lump *lp = fp->lv + np->l0 + i;
116 if (lp->fl & L_DETAIL)
119 cx = array_add(lumps);
121 make_convex(cx, fp, lp);
123 geom = dCreateConvex(node,
124 cx->planes, cx->nplanes,
125 cx->points, cx->npoints,
128 dGeomSetCategoryBits(geom, CAT_WORLD);
129 dGeomSetCollideBits (geom, CAT_OBJECT);
131 if (body) dGeomSetBody(geom, body);
134 if (np->ni >= 0) build_node(body, node, fp->nv + np->ni, fp);
135 if (np->nj >= 0) build_node(body, node, fp->nv + np->nj, fp);
138 static void build_branch(dBodyID body, dSpaceID root,
142 dSpaceID branch = dHashSpaceCreate(root);
144 build_node(body, branch, fp->nv + bp->ni, fp);
147 void sol_init_sim(struct s_file *fp)
155 world = dWorldCreate();
156 space = dHashSpaceCreate(0);
157 group = dJointGroupCreate(0);
159 lumps = array_new(sizeof (struct convex));
161 bodies = calloc(fp->bc, sizeof (dBodyID));
162 balls = calloc(fp->uc, sizeof (dBodyID));
164 for (i = 0; i < fp->bc; i++)
166 struct s_body *bp = fp->bv + i;
170 bodies[i] = dBodyCreate(world);
171 dBodySetKinematic(bodies[i]);
176 build_branch(bodies[i], space, bp, fp);
182 sol_body_p(p, fp, bp->pi, 0.0f);
183 sol_body_w(w, fp, bp);
185 dBodySetPosition(bodies[i], p[0], p[1], p[2]);
186 dBodySetAngularVel(bodies[i], w[0], w[1], w[2]);
190 for (i = 0; i < fp->uc; i++)
192 balls[i] = dBodyCreate(world);
194 geom = dCreateSphere(space, fp->uv[i].r);
196 dGeomSetCategoryBits(geom, CAT_OBJECT);
197 dGeomSetCollideBits(geom, CAT_WORLD);
198 dGeomSetData(geom, fp->uv + i);
199 dGeomSetBody(geom, balls[i]);
201 dBodySetPosition(balls[i],
208 void sol_quit_sim(void)
213 while (array_len(lumps))
215 struct convex *cx = array_get(lumps, array_len(lumps) - 1);
222 dJointGroupDestroy(group);
223 dSpaceDestroy(space);
224 dWorldDestroy(world);
229 /*---------------------------------------------------------------------------*/
231 static const dVector3 v_null = { 0.0, 0.0, 0.0 };
233 static const dReal *geomvel(dGeomID g)
236 return (b = dGeomGetBody(g)) ? dBodyGetLinearVel(b) : v_null;
239 static const dReal *pointvel(dGeomID g, dVector3 p)
243 if ((b = dGeomGetBody(g)))
246 dBodyGetPointVel(b, p[0], p[1], p[2], v);
254 * Compute the "energy" of the impact, to determine the sound amplitude.
256 static float bump(dContactGeom *contact)
259 v_sub(r, geomvel(contact->g1), pointvel(contact->g2, contact->pos));
260 return fabsf(v_dot(contact->normal, r));
263 static void spin(dContactGeom *contact)
266 const dReal *p, *v, *w;
269 if ((up = dGeomGetData(contact->g1)))
272 p = dGeomGetPosition(contact->g1);
273 v = geomvel(contact->g1);
274 w = pointvel(contact->g2, contact->pos);
278 up = dGeomGetData(contact->g2);
280 p = dGeomGetPosition(contact->g2);
281 v = geomvel(contact->g2);
282 w = pointvel(contact->g1, contact->pos);
285 v_sub(r, p, contact->pos);
288 /* Find the new angular velocity. */
291 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
294 static void collide(void *data, dGeomID o1, dGeomID o2)
296 dContact contacts[8];
301 float *b = (float *) data;
304 if (dGeomIsSpace(o1) || dGeomIsSpace(o2))
306 dSpaceCollide2(o1, o2, data, collide);
310 if ((n = dCollide(o1, o2, 8, &contacts[0].geom, sizeof (dContact))) > 0)
312 for (i = 0; i < n; i++)
314 if (*b < (d = bump(&contacts[i].geom)))
317 spin(&contacts[i].geom);
319 contacts[i].surface.mode = dContactBounce;
320 contacts[i].surface.mu = 0;
321 contacts[i].surface.bounce = 0.718;
322 contacts[i].surface.bounce_vel = 0;
324 joint = dJointCreateContact(world, group, contacts + i);
326 dJointAttach(joint, dGeomGetBody(o1), dGeomGetBody(o2));
331 /*---------------------------------------------------------------------------*/
333 static void import_state(struct s_file *fp, float dt)
337 for (i = 0; i < fp->uc; i++)
339 dBodySetPosition(balls[i],
344 dBodySetLinearVel(balls[i],
349 dGeomSphereSetRadius(dBodyGetFirstGeom(balls[i]), fp->uv[i].r);
352 for (i = 0; i < fp->bc; i++)
354 struct s_body *bp = fp->bv + i;
355 float p[3], v[3], w[3];
359 sol_body_p(p, fp, bp->pi, bp->t);
360 sol_body_v(v, fp, bp->pi, bp->t, dt);
361 sol_body_w(w, fp, bp);
363 dBodySetPosition(bodies[i], p[0], p[1], p[2]);
364 dBodySetLinearVel(bodies[i], v[0], v[1], v[2]);
365 dBodySetAngularVel(bodies[i], w[0], w[1], w[2]);
370 static void export_state(struct s_file *fp)
375 for (i = 0; i < fp->uc; i++)
377 struct s_ball *up = fp->uv + i;
379 v = dBodyGetPosition(balls[i]);
382 v = dBodyGetLinearVel(balls[i]);
386 for (i = 0; i < fp->bc; i++)
388 struct s_body *bp = fp->bv + i;
392 v = dBodyGetQuaternion(bodies[i]);
398 /*---------------------------------------------------------------------------*/
400 float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
405 /* The simulation is advanced only once, commands don't accumulate. */
409 import_state(fp, dt);
411 dSpaceCollide(space, &b, collide);
412 dWorldSetGravity(world, g[0], g[1], g[2]);
413 dWorldQuickStep(world, dt);
414 dJointGroupEmpty(group);
416 sol_body_step(fp, dt);
417 sol_swch_step(fp, dt);
418 sol_ball_step(fp, dt);
422 cmd.type = CMD_STEP_SIMULATION;
429 /*---------------------------------------------------------------------------*/