* <real key="speed" name="Travel time" value="1.0">Duration of the trip along this path segment, in seconds. The default is "1.0".</real>
* <boolean key="state" name="State" value="1">Determines whether the path is enabled. An object will only move along an enabled path. An object may be stopped and started by toggling the state of the path to which it is attached. "0" means no, "1" means yes. The default is 1.</boolean>
* <boolean key="smooth" name="Smooth" value="1">Determines whether an object moves smoothly along this path segment or at a constant speed. "0" means no, "1" means yes. The default is 1.</boolean>
+* <angles key="angles" name="Orientation" value="0 0 0">Defines the final orientation of the object at this path_corner. The first two values are angles giving the axis of rotation (first angle is inverse elevation, second angle is azimuth). The third value is an angle giving the amount of rotation about the axis. As the object travels between two path corners, its orientation is interpolated between the orientations of the corners.</angles>
</point>
struct s_body *bp = file.bv + i;
struct s_path *pp = file.pv + bp->pi;
- if (bp->pi >= 0 && pp->f && (bp->fl & P_ROTATING) == 0)
+ if (bp->pi >= 0 && pp->f)
bp->t += dt;
}
break;
break;
case CMD_BODY_ORIENTATION:
- q_cpy(file.bv[cmd->bodyorient.bi].e, cmd->bodyorient.e);
break;
case CMD_NONE:
pp->p[1] = +z / SCALE;
pp->p[2] = -y / SCALE;
}
+
+ if (strcmp(k[i], "angles") == 0)
+ {
+ float x = 0.0f, y = 0.0f, z = 0.0f;
+
+ /* Pitch, yaw and roll. */
+
+ sscanf(v[i], "%f %f %f", &x, &y, &z);
+
+ /*
+ * Find the direction vector from pitch and yaw, use it as
+ * the rotation axis.
+ */
+
+ x = V_RAD(-x);
+ y = V_RAD(+y);
+
+ pp->e[1] = fcosf(y) * fcosf(x);
+ pp->e[2] = fsinf(x);
+ pp->e[3] = -fsinf(y) * fcosf(x);
+
+ /* Use roll as the rotation angle. */
+
+ z = V_RAD(+z) * 0.5f;
+
+ pp->e[0] = fcosf(z);
+ v_scl(pp->e + 1, pp->e + 1, fsinf(z));
+
+ pp->fl |= P_ORIENTED;
+ }
}
}
else if (strcmp(k[i], "origin") == 0)
sscanf(v[i], "%f %f %f", &x, &y, &z);
- else if (strcmp(k[i], "classname") == 0 &&
- strcmp(v[i], "func_rotating") == 0)
- bp->fl |= P_ROTATING;
-
else if (read_dict_entries && strcmp(k[i], "classname") != 0)
make_dict(fp, k[i], v[i]);
}
make_body(fp, k, v, c, l0);
}
if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
- if (!strcmp(v[i], "func_rotating")) make_body(fp, k, v, c, l0);
if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
}
SOL_VER_MINIMUM = 6,
SOL_VER_LUMP_POLY,
SOL_VER_BODY_FLAG,
- SOL_VER_CURRENT = SOL_VER_BODY_FLAG
+ SOL_VER_PATH_FLAGS,
+ SOL_VER_CURRENT = SOL_VER_PATH_FLAGS
};
#define MAGIC 0x4c4f53af
get_index(fin, &pp->pi);
get_index(fin, &pp->f);
get_index(fin, &pp->s);
+
+ if (sol_version >= SOL_VER_PATH_FLAGS)
+ get_index(fin, &pp->fl);
+
+ pp->e[0] = 1.0f;
+ pp->e[1] = 0.0f;
+ pp->e[2] = 0.0f;
+ pp->e[3] = 0.0f;
+
+ if (pp->fl & P_ORIENTED)
+ get_array(fin, pp->e, 4);
}
static void sol_load_body(fs_file fin, struct s_body *bp)
if (sol_version >= SOL_VER_BODY_FLAG)
get_index(fin, &bp->fl);
-
- bp->e[0] = 1.0f;
- bp->e[1] = 0.0f;
- bp->e[2] = 0.0f;
- bp->e[3] = 0.0f;
}
static void sol_load_item(fs_file fin, struct s_item *hp)
put_index(fout, &pp->pi);
put_index(fout, &pp->f);
put_index(fout, &pp->s);
+ put_index(fout, &pp->fl);
+
+ if (pp->fl & P_ORIENTED)
+ put_array(fout, pp->e, 4);
}
static void sol_stor_body(fs_file fout, struct s_body *bp)
#define ITEM_GROW 2
#define ITEM_SHRINK 3
-/* Body flags. */
+/* Path flags. */
-#define P_ROTATING 1
+#define P_ORIENTED 1
/*---------------------------------------------------------------------------*/
struct s_path
{
float p[3]; /* starting position */
+ float e[4]; /* orientation (quaternion) */
float t; /* travel time */
int pi;
int f; /* enable flag */
int s; /* smooth flag */
+
+ int fl; /* flags */
+
+ /* TODO: merge enable and smooth into flags. */
};
struct s_body
{
float t; /* time on current path */
- float e[4]; /* orientation (quaternion) */
GLuint ol; /* opaque geometry list */
GLuint tl; /* transparent geometry list */
}
}
+void sol_body_e(float e[4],
+ const struct s_file *fp,
+ const struct s_body *bp)
+{
+ struct s_path *pp = fp->pv + bp->pi;
+
+ if (bp->pi >= 0)
+ {
+ struct s_path *pq = fp->pv + pp->pi;
+
+ if (pp->fl & P_ORIENTED || pq->fl & P_ORIENTED)
+ {
+ q_slerp(e, pp->e, pq->e, bp->t / pp->t);
+ return;
+ }
+ }
+
+ e[0] = 1.0f;
+ e[1] = 0.0f;
+ e[2] = 0.0f;
+ e[3] = 0.0f;
+}
+
void sol_body_w(float w[3],
const struct s_file *fp,
const struct s_body *bp)
{
- if (bp->fl & P_ROTATING)
+ struct s_path *pp = fp->pv + bp->pi;
+
+ if (bp->pi >= 0 && pp->f)
{
- struct s_path *pp = fp->pv + bp->pi;
+ struct s_path *pq = fp->pv + pp->pi;
- if (bp->pi >= 0 && pp->f)
+ if (pp->fl & P_ORIENTED || pq->fl & P_ORIENTED)
{
- struct s_path *pq = fp->pv + pp->pi;
+ float d[4], i[4], a;
- if (pp->pi != bp->pi)
- {
- v_sub(w, pq->p, pp->p);
- v_nrm(w, w);
- v_scl(w, w, (1.0f / pp->t) * 2 * V_PI);
- }
- else
+ /*
+ * a * d = b
+ * d = b / a
+ * d = b * (1 / a)
+ */
+
+ i[0] = pp->e[0];
+ i[1] = -pp->e[1];
+ i[2] = -pp->e[2];
+ i[3] = -pp->e[3];
+
+ q_mul(d, pq->e, i);
+ q_nrm(d, d);
+
+ /* Match slerp by using the short path. */
+
+ if (d[0] < 0)
{
- w[0] = 0.0f;
- w[1] = (1.0f / pp->t) * 2 * V_PI;
- w[2] = 0.0f;
+ d[0] = -d[0];
+ d[1] = -d[1];
+ d[2] = -d[2];
+ d[3] = -d[3];
}
+
+ q_as_axisangle(d, w, &a);
+ v_scl(w, w, a / pp->t);
+ return;
}
- else
- {
- w[0] = 0.0f;
- w[1] = 0.0f;
- w[2] = 0.0f;
- }
- }
- else
- {
- w[0] = 0.0f;
- w[1] = 0.0f;
- w[2] = 0.0f;
}
+
+ w[0] = 0.0f;
+ w[1] = 0.0f;
+ w[2] = 0.0f;
}
/*---------------------------------------------------------------------------*/
if (bp->pi >= 0 && pp->f)
{
- if (bp->fl & P_ROTATING)
- {
- float d[4], e[4], w[3];
-
- sol_body_w(w, fp, bp);
-
- q_by_axisangle(d, w, v_len(w) * dt);
-
- q_mul(e, bp->e, d);
- q_nrm(bp->e, e);
+ bp->t = (t += dt);
- cmd.type = CMD_BODY_ORIENTATION;
- cmd.bodyorient.bi = i;
- q_cpy(cmd.bodyorient.e, bp->e);
- sol_cmd_enq(&cmd);
- }
- else
+ if (t >= pp->t)
{
- bp->t = (t += dt);
-
- if (t >= pp->t)
- {
- bp->t = 0;
- bp->pi = pp->pi;
+ bp->t = 0;
+ bp->pi = pp->pi;
- cmd.type = CMD_BODY_TIME;
- cmd.bodytime.bi = i;
- cmd.bodytime.t = bp->t;
- sol_cmd_enq(&cmd);
+ cmd.type = CMD_BODY_TIME;
+ cmd.bodytime.bi = i;
+ cmd.bodytime.t = bp->t;
+ sol_cmd_enq(&cmd);
- cmd.type = CMD_BODY_PATH;
- cmd.bodypath.bi = i;
- cmd.bodypath.pi = bp->pi;
- sol_cmd_enq(&cmd);
- }
+ cmd.type = CMD_BODY_PATH;
+ cmd.bodypath.bi = i;
+ cmd.bodypath.pi = bp->pi;
+ sol_cmd_enq(&cmd);
}
}
}
void sol_body_p(float p[3], const struct s_file *fp, int pi, float t);
void sol_body_v(float v[3], const struct s_file *fp, int pi, float t, float dt);
+void sol_body_e(float e[3], const struct s_file *fp, const struct s_body *bp);
void sol_body_w(float w[3], const struct s_file *fp, const struct s_body *bp);
void sol_rotate(float e[3][3], const float w[3], float dt);
static void sol_draw_list(const struct s_file *fp,
const struct s_body *bp, GLuint list)
{
- float p[3], u[3], a;
+ float p[3], e[4], u[3], a;
sol_body_p(p, fp, bp->pi, bp->t);
+ sol_body_e(e, fp, bp);
- q_as_axisangle(bp->e, u, &a);
+ q_as_axisangle(e, u, &a);
a = V_DEG(a);
glPushMatrix();
static void sol_shad_list(const struct s_file *fp,
const struct s_body *bp, GLuint list)
{
- float p[3], u[3], a;
+ float p[3], e[4], u[3], a;
sol_body_p(p, fp, bp->pi, bp->t);
+ sol_body_e(e, fp, bp);
- q_as_axisangle(bp->e, u, &a);
+ q_as_axisangle(e, u, &a);
a = V_DEG(a);
glPushMatrix();
const struct s_file *fp,
const struct s_body *bp)
{
- float U[3], O[3], W[3], A[3], u, t = dt;
+ float U[3], O[3], E[4], W[3], A[3], u, t = dt;
const struct s_node *np = fp->nv + bp->ni;
sol_body_p(O, fp, bp->pi, bp->t);
sol_body_v(W, fp, bp->pi, bp->t, dt);
+ sol_body_e(E, fp, bp);
sol_body_w(A, fp, bp);
/*
* v = w x p
*/
- if (bp->fl & P_ROTATING)
+ if (E[0] != 1.0f || v_dot(A, A))
{
+ /* The body has a non-identity orientation or it is rotating. */
+
struct s_ball ball = *up;
float e[4], w[3], v[3];
- e[0] = bp->e[0];
- e[1] = -bp->e[1];
- e[2] = -bp->e[2];
- e[3] = -bp->e[3];
+ e[0] = E[0];
+ e[1] = -E[1];
+ e[2] = -E[2];
+ e[3] = -E[3];
w[0] = -A[0];
w[1] = -A[1];
/* Transform velocity. */
- q_rot(ball.v, e, up->v);
+ v_sub(v, up->v, W);
+ q_rot(ball.v, e, v);
/* Also add the velocity from rotation. */
float d[4];
q_by_axisangle(d, A, v_len(A) * u);
- q_mul(e, bp->e, d);
+ q_mul(e, E, d);
q_nrm(e, e);
q_rot(T, e, U);
+
v_crs(V, A, T);
+ v_add(V, V, W);
+
v_add(T, O, T);
+ v_mad(O, T, W, u);
t = u;
}