3 #include "cgmath/cgmath.h"
9 static struct mobject *mobj_create(int num);
10 static void swstate(struct mobject *mobj, int st);
11 static void update(struct mobject *mobj, float tsec);
12 static float eval(struct mobject *mobj, cgm_vec3 *pos);
14 static void upd_sflake_ball(struct mobject *mobj, struct mball *ball, float tsec, float t);
15 static int calc_num_balls(int depth);
16 static int gen_sflake(cgm_vec4 *sarr, int num, int depth, float x, float y, float z, float rad);
18 static void upd_sgi_caps(struct mobject *mobj, struct mcapsule *caps, float tsec, float t);
20 static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos);
21 static float easein(float x);
22 static float easeout(float x);
25 static struct mobject *mobj_create(int num)
30 mobj = calloc_nf(1, sizeof *mobj);
32 mobj->idlepos = malloc_nf(num * sizeof *mobj->idlepos);
33 mobj->mot = malloc_nf(num * sizeof *mobj->mot);
35 for(i=0; i<num; i++) {
36 mobj->mot[i].x = 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f;
37 mobj->mot[i].y = 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f;
38 mobj->mot[i].z = 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f;
42 mobj->swstate = swstate;
43 mobj->update = update;
47 swstate(mobj, MOBJ_IDLE);
51 static void swstate(struct mobject *mobj, int st)
53 if(st == mobj->state) return;
54 if(st == MOBJ_GRABING && mobj->state != MOBJ_IDLE) return;
55 if(st == MOBJ_DROPPING && mobj->state != MOBJ_HELD && mobj->state != MOBJ_GRABING) {
61 if(mobj->state != MOBJ_IDLE) return;
65 if(mobj->state != MOBJ_HELD && mobj->state != MOBJ_GRABING) {
71 mobj->pos.x = mobj->pos.z = 0.0f;
72 mobj->pos.y = -BBOX_YSZ * 0.5f;
77 mobj->tstart = (float)time_msec / 1000.0f;
80 static void update(struct mobject *mobj, float tsec)
84 struct mcapsule *caps;
89 count = mobj->num_balls + mobj->num_caps;
91 if(mobj->state != MOBJ_IDLE) {
92 cgm_midentity(mobj->xform);
93 cgm_mrotate_x(mobj->xform, tsec);
94 cgm_mrotate_y(mobj->xform, tsec);
95 cgm_mtranslate(mobj->xform, mobj->pos.x, mobj->pos.y, mobj->pos.z);
97 if(mobj->state != MOBJ_HELD) {
98 for(i=0; i<count; i++) {
99 mobj->idlepos[i].x = sin(tsec * mobj->mot[i].x + mobj->mot[i].y) * mobj->mot[i].z * 4.0f;
100 mobj->idlepos[i].z = cos(tsec * mobj->mot[i].z + mobj->mot[i].y) * mobj->mot[i].x * 4.0f;
101 mobj->idlepos[i].y = -BBOX_YSZ * 0.45f;
105 idleptr = mobj->idlepos;
110 switch(mobj->state) {
113 for(i=0; i<mobj->num_balls; i++) {
114 ball->pos = idleptr[i];
115 ball->energy = motptr[i].w;
118 idleptr += mobj->num_balls;
119 motptr += mobj->num_balls;
122 for(i=0; i<mobj->num_caps; i++) {
123 caps->end[0] = caps->end[1] = idleptr[i];
124 caps->energy = motptr[i].w;
131 if((elapsed = tsec - mobj->tstart) >= TRANSDUR) {
132 mobj->swstate(mobj, MOBJ_HELD);
135 t = easeout((tsec - mobj->tstart) / TRANSDUR);
139 if((elapsed = tsec - mobj->tstart) >= TRANSDUR) {
140 mobj->swstate(mobj, MOBJ_IDLE);
143 t = easein((tsec - mobj->tstart) / TRANSDUR);
146 for(i=0; i<mobj->num_balls; i++) {
147 mobj->upd_ball(mobj, ball++, tsec, t);
149 for(i=0; i<mobj->num_caps; i++) {
150 mobj->upd_caps(mobj, caps++, tsec, t);
155 for(i=0; i<mobj->num_balls; i++) {
156 mobj->upd_ball(mobj, ball++, tsec, 0);
158 for(i=0; i<mobj->num_caps; i++) {
159 mobj->upd_caps(mobj, caps++, tsec, 0);
165 static float eval(struct mobject *mobj, cgm_vec3 *pos)
168 float dsq, energy = 0.0f;
169 struct mball *ball = mobj->balls;
170 struct mcapsule *caps = mobj->caps;
172 for(i=0; i<mobj->num_balls; i++) {
173 dsq = cgm_vdist_sq(&ball->pos, pos);
174 energy += ball->energy / dsq;
178 for(i=0; i<mobj->num_caps; i++) {
179 dsq = capsule_distsq(caps, pos);
180 energy += caps->energy / dsq;
187 /* ---- sphereflake ---- */
188 #define SF_MAX_DEPTH 2
189 static cgm_vec4 *sfsph;
191 struct mobject *metaobj_sflake(void)
194 struct mobject *mobj;
196 num_balls = calc_num_balls(SF_MAX_DEPTH);
198 mobj = mobj_create(num_balls);
200 mobj->num_balls = num_balls;
201 mobj->balls = malloc_nf(num_balls * sizeof *mobj->balls);
202 sfsph = malloc_nf(num_balls * sizeof *sfsph);
204 gen_sflake(sfsph, 0, SF_MAX_DEPTH, 0, 0, 0, 20);
206 mobj->upd_ball = upd_sflake_ball;
210 static void upd_sflake_ball(struct mobject *mobj, struct mball *ball, float tsec, float t)
212 int idx = ball - mobj->balls;
215 switch(mobj->state) {
219 cgm_vcons(&pos, sfsph[idx].x, sfsph[idx].y, sfsph[idx].z);
220 cgm_vmul_m4v3(&pos, mobj->xform);
221 cgm_vlerp(&ball->pos, mobj->idlepos + idx, &pos, t);
222 ball->energy = cgm_lerp(mobj->mot[idx].w, sfsph[idx].w, t);
226 cgm_vcons(&ball->pos, sfsph[idx].x, sfsph[idx].y, sfsph[idx].z);
227 cgm_vmul_m4v3(&ball->pos, mobj->xform);
228 ball->energy = sfsph[idx].w;
233 static int calc_num_balls(int depth)
236 return calc_num_balls(depth - 1) * 6 + 1;
239 static int gen_sflake(cgm_vec4 *sarr, int num, int depth, float x, float y, float z, float rad)
256 subnum += gen_sflake(sarr, num + subnum, depth - 1, x + offs, y, z, subrad);
257 subnum += gen_sflake(sarr, num + subnum, depth - 1, x - offs, y, z, subrad);
258 subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y + offs, z, subrad);
259 subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y - offs, z, subrad);
260 subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y, z + offs, subrad);
261 subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y, z - offs, subrad);
265 /* ---- SGI logo ---- */
267 static const cgm_vec3 sgiv[] = {
268 {2.794170, 4.254175, 2.738066},
269 {2.794170, 4.254174, -4.358471},
270 {-2.173414, 4.254174, -4.358471},
271 {-2.173414, -2.842363, -4.358470},
272 {4.923134, -2.842363, -4.358471},
273 {4.923134, 2.125212, -4.358471},
274 {4.923134, 2.125212, 2.738066},
275 {4.923134, -4.971326, 2.738067},
276 {4.923134, -4.971326, -2.229511},
277 {-2.173413, -4.971326, -2.229511},
278 {-2.173413, -4.971325, 4.867042},
279 {2.794170, -4.971325, 4.867042},
280 {2.794170, 2.125213, 4.867042},
281 {-4.302382, 2.125213, 4.867042},
282 {-4.302383, -2.842362, 4.867042},
283 {-4.302382, -2.842363, -2.229511},
284 {-4.302382, 4.254175, -2.229512},
285 {-4.302383, 4.254175, 2.738066}
287 #define NUM_SGI_VERTS (sizeof sgiv / sizeof *sgiv)
288 static float sgimat[16];
290 struct mobject *metaobj_sgi(void)
293 struct mobject *mobj;
295 cgm_midentity(sgimat);
296 cgm_mrotate_y(sgimat, -M_PI / 4.0f);
297 cgm_mrotate_x(sgimat, M_PI / 4.0f);
298 cgm_mtranslate(sgimat, 0, -4, 0);
300 mobj = mobj_create(NUM_SGI_VERTS);
302 mobj->num_caps = NUM_SGI_VERTS;
303 mobj->caps = calloc_nf(mobj->num_caps, sizeof *mobj->caps);
305 for(i=0; i<mobj->num_caps; i++) {
306 mobj->caps[i].energy = 0.7;
309 mobj->swstate = swstate;
310 mobj->upd_caps = upd_sgi_caps;
314 #define LOGOSCALE 0.55f
315 static void upd_sgi_caps(struct mobject *mobj, struct mcapsule *caps, float tsec, float t)
319 static cgm_vec3 prev_pos;
321 idx0 = caps - mobj->caps;
322 idx1 = idx0 >= mobj->num_caps - 1 ? 0 : idx0 + 1;
324 switch(mobj->state) {
330 cgm_vscale(pos, LOGOSCALE);
331 cgm_vmul_m4v3(pos, mobj->xform);
332 cgm_vlerp(caps->end, mobj->idlepos + idx0, pos, t);
334 caps->end[0] = prev_pos;
337 cgm_vscale(pos + 1, LOGOSCALE);
338 cgm_vmul_m4v3(pos + 1, mobj->xform);
339 cgm_vlerp(caps->end + 1, mobj->idlepos + idx1, pos + 1, t);
340 prev_pos = caps->end[1];
341 /*caps->energy = cgm_lerp(mobj->mot[idx].w, sfsph[idx].w, t);*/
347 cgm_vscale(pos, LOGOSCALE);
348 cgm_vmul_m4v3(pos, mobj->xform);
349 caps->end[0] = pos[0];
351 caps->end[0] = prev_pos;
354 cgm_vscale(pos + 1, LOGOSCALE);
355 cgm_vmul_m4v3(pos + 1, mobj->xform);
356 prev_pos = caps->end[1] = pos[1];
359 caps->len = cgm_vdist(caps->end, caps->end + 1);
362 static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos)
365 cgm_vec3 pp, dir, pdir;
367 dir = c->end[1]; cgm_vsub(&dir, c->end);
369 float s = 1.0f / c->len;
374 pdir = *pos; cgm_vsub(&pdir, c->end);
375 t = cgm_vdot(&dir, &pdir);
378 return cgm_vdist_sq(c->end, pos);
381 return cgm_vdist_sq(c->end + 1, pos);
385 cgm_vadd_scaled(&pp, &dir, t);
386 return cgm_vdist_sq(&pp, pos);
389 static float easein(float x)
394 static float easeout(float x)
396 return 1.0f - pow(1.0f - x, 3.0f);