2 /* Random code used in more than one place. */
11 /*---------------------------------------------------------------------------*/
13 static float erp(float t)
15 return 3.0f * t * t - 2.0f * t * t * t;
19 static float derp(float t)
21 return 6.0f * t - 6.0f * t * t;
25 void sol_body_p(float p[3], const struct s_file *fp, int pi, float t)
31 const struct s_path *pp = fp->pv + pi;
32 const struct s_path *pq = fp->pv + pp->pi;
34 float s = MIN(t / pp->t, 1.0f);
36 v_sub(v, pq->p, pp->p);
37 v_mad(p, pp->p, v, pp->s ? erp(s) : s);
47 void sol_body_v(float v[3],
48 const struct s_file *fp,
49 int pi, float t, float dt)
51 if (pi >= 0 && fp->pv[pi].f)
55 sol_body_p(p, fp, pi, t);
56 sol_body_p(q, fp, pi, t + dt);
72 void sol_body_w(float w[3],
73 const struct s_file *fp,
74 const struct s_body *bp)
76 if (bp->fl & P_ROTATING)
78 struct s_path *pp = fp->pv + bp->pi;
80 if (bp->pi >= 0 && pp->f)
82 struct s_path *pq = fp->pv + pp->pi;
86 v_sub(w, pq->p, pp->p);
88 v_scl(w, w, (1.0f / pp->t) * 2 * V_PI);
93 w[1] = (1.0f / pp->t) * 2 * V_PI;
112 /*---------------------------------------------------------------------------*/
115 * Integrate the rotation of the given basis E under angular velocity W
118 void sol_rotate(float e[3][3], const float w[3], float dt)
122 float a[3], M[16], f[3][3];
124 /* Compute the rotation matrix. */
127 m_rot(M, a, v_len(w) * dt);
129 /* Apply it to the basis. */
131 m_vxfm(f[0], M, e[0]);
132 m_vxfm(f[1], M, e[1]);
133 m_vxfm(f[2], M, e[2]);
135 /* Re-orthonormalize the basis. */
137 v_crs(e[2], f[0], f[1]);
138 v_crs(e[1], f[2], f[0]);
139 v_crs(e[0], f[1], f[2]);
147 /*---------------------------------------------------------------------------*/
150 * Compute the new angular velocity and orientation of a ball pendulum.
151 * A gives the accelleration of the ball. G gives the gravity vector.
153 void sol_pendulum(struct s_ball *up,
155 const float g[3], float dt)
157 float v[3], A[3], F[3], r[3], Y[3], T[3] = { 0.0f, 0.0f, 0.0f };
159 const float m = 5.000f;
160 const float ka = 0.500f;
161 const float kd = 0.995f;
163 /* Find the total force over DT. */
168 /* Find the force. */
172 /* Find the position of the pendulum. */
174 v_scl(r, up->E[1], -up->r);
176 /* Find the torque on the pendulum. */
178 if (fabsf(v_dot(r, F)) > 0.0f)
181 /* Apply the torque and dampen the angular velocity. */
183 v_mad(up->W, up->W, T, dt);
184 v_scl(up->W, up->W, kd);
186 /* Apply the angular velocity to the pendulum basis. */
188 sol_rotate(up->E, up->W, dt);
190 /* Apply a torque turning the pendulum toward the ball velocity. */
192 v_mad(v, up->v, up->E[1], v_dot(up->v, up->E[1]));
193 v_crs(Y, v, up->E[2]);
194 v_scl(Y, up->E[1], 2 * v_dot(Y, up->E[1]));
196 sol_rotate(up->E, Y, dt);
199 /*---------------------------------------------------------------------------*/
202 * Compute the states of all switches after DT seconds have passed.
204 void sol_swch_step(struct s_file *fp, float dt)
210 for (xi = 0; xi < fp->xc; xi++)
212 struct s_swch *xp = fp->xv + xi;
214 volatile float t = xp->t;
225 do /* Tortoise and hare cycle traverser. */
227 fp->pv[pi].f = xp->f0;
228 fp->pv[pj].f = xp->f0;
230 cmd.type = CMD_PATH_FLAG;
231 cmd.pathflag.pi = pi;
232 cmd.pathflag.f = fp->pv[pi].f;
243 cmd.type = CMD_SWCH_TOGGLE;
244 cmd.swchtoggle.xi = xi;
252 * Compute the positions of all bodies after DT seconds have passed.
254 void sol_body_step(struct s_file *fp, float dt)
260 for (i = 0; i < fp->bc; i++)
262 struct s_body *bp = fp->bv + i;
263 struct s_path *pp = fp->pv + bp->pi;
265 volatile float t = bp->t;
267 if (bp->pi >= 0 && pp->f)
269 if (bp->fl & P_ROTATING)
271 cmd.type = CMD_BODY_ORIENTATION;
272 cmd.bodyorient.bi = i;
273 q_cpy(cmd.bodyorient.e, bp->e);
285 cmd.type = CMD_BODY_TIME;
287 cmd.bodytime.t = bp->t;
290 cmd.type = CMD_BODY_PATH;
292 cmd.bodypath.pi = bp->pi;
301 * Compute the positions of all balls after DT seconds have passed.
303 void sol_ball_step(struct s_file *fp, float dt)
307 for (i = 0; i < fp->uc; i++)
309 struct s_ball *up = fp->uv + i;
311 v_mad(up->p, up->p, up->v, dt);
313 sol_rotate(up->e, up->w, dt);
317 /*---------------------------------------------------------------------------*/
319 int sol_item_test(struct s_file *fp, float *p, float item_r)
321 const float *ball_p = fp->uv->p;
322 const float ball_r = fp->uv->r;
326 for (hi = 0; hi < fp->hc; hi++)
330 r[0] = ball_p[0] - fp->hv[hi].p[0];
331 r[1] = ball_p[1] - fp->hv[hi].p[1];
332 r[2] = ball_p[2] - fp->hv[hi].p[2];
334 if (fp->hv[hi].t != ITEM_NONE && v_len(r) < ball_r + item_r)
336 p[0] = fp->hv[hi].p[0];
337 p[1] = fp->hv[hi].p[1];
338 p[2] = fp->hv[hi].p[2];
346 struct s_goal *sol_goal_test(struct s_file *fp, float *p, int ui)
348 const float *ball_p = fp->uv[ui].p;
349 const float ball_r = fp->uv[ui].r;
352 for (zi = 0; zi < fp->zc; zi++)
356 r[0] = ball_p[0] - fp->zv[zi].p[0];
357 r[1] = ball_p[2] - fp->zv[zi].p[2];
360 if (v_len(r) < fp->zv[zi].r - ball_r &&
361 ball_p[1] > fp->zv[zi].p[1] &&
362 ball_p[1] < fp->zv[zi].p[1] + GOAL_HEIGHT / 2)
364 p[0] = fp->zv[zi].p[0];
365 p[1] = fp->zv[zi].p[1];
366 p[2] = fp->zv[zi].p[2];
375 * Test if the ball UI is inside a jump. Return 1 if yes and fill P
376 * with the destination position, return 0 if not, and return 2 if the
377 * ball is on the border of a jump.
379 int sol_jump_test(struct s_file *fp, float *p, int ui)
381 const float *ball_p = fp->uv[ui].p;
382 const float ball_r = fp->uv[ui].r;
387 for (ji = 0; ji < fp->jc; ji++)
391 r[0] = ball_p[0] - fp->jv[ji].p[0];
392 r[1] = ball_p[2] - fp->jv[ji].p[2];
395 l = v_len(r) - fp->jv[ji].r;
397 ball_p[1] > fp->jv[ji].p[1] &&
398 ball_p[1] < fp->jv[ji].p[1] + JUMP_HEIGHT / 2)
402 p[0] = fp->jv[ji].q[0] + (ball_p[0] - fp->jv[ji].p[0]);
403 p[1] = fp->jv[ji].q[1] + (ball_p[1] - fp->jv[ji].p[1]);
404 p[2] = fp->jv[ji].q[2] + (ball_p[2] - fp->jv[ji].p[2]);
416 * Test and process the event the ball UI enters a switch. Return 1 if
417 * a visible switch is activated, return 0 otherwise (no switch is
418 * activated or only invisible switches).
420 int sol_swch_test(struct s_file *fp, int ui)
422 const float *ball_p = fp->uv[ui].p;
423 const float ball_r = fp->uv[ui].r;
429 for (xi = 0; xi < fp->xc; xi++)
431 struct s_swch *xp = fp->xv + xi;
433 /* FIXME enter/exit events don't work for timed switches */
435 if (xp->t0 == 0 || xp->f == xp->f0)
440 r[0] = ball_p[0] - xp->p[0];
441 r[1] = ball_p[2] - xp->p[2];
444 l = v_len(r) - xp->r;
447 ball_p[1] > xp->p[1] &&
448 ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
450 if (!xp->e && l < - ball_r)
455 /* The ball enters. */
461 cmd.type = CMD_SWCH_ENTER;
462 cmd.swchenter.xi = xi;
466 /* Toggle the state, update the path. */
468 xp->f = xp->f ? 0 : 1;
470 cmd.type = CMD_SWCH_TOGGLE;
471 cmd.swchtoggle.xi = xi;
474 do /* Tortoise and hare cycle traverser. */
476 fp->pv[pi].f = xp->f;
477 fp->pv[pj].f = xp->f;
479 cmd.type = CMD_PATH_FLAG;
480 cmd.pathflag.pi = pi;
481 cmd.pathflag.f = fp->pv[pi].f;
490 /* It toggled to non-default state, start the timer. */
495 /* If visible, set the result. */
502 /* The ball exits. */
508 cmd.type = CMD_SWCH_EXIT;
509 cmd.swchexit.xi = xi;
517 /*---------------------------------------------------------------------------*/