#include "cgmath/cgmath.h"
#include "metaobj.h"
-#define BBOX_XSZ 16
-#define BBOX_YSZ 15
-#define BBOX_ZSZ 10
-#define VOX_RES 24
#define BBOX_HXSZ (BBOX_XSZ / 2.0f)
#define BBOX_HYSZ (BBOX_YSZ / 2.0f)
#define VBUF_MAX_TRIS 256
#define VBUF_SIZE (VBUF_MAX_TRIS * 3)
+unsigned long time_msec;
+
static struct g3d_vertex *vbuf;
static struct metasurface *msurf;
-static struct mobject **mobj;
+static struct mobject **mobjects, *mobj;
#define NUM_OBJ 2
static int num_mobj, cur_obj;
-static int grabbed;
static int mousebn[3];
static int mousex, mousey;
vbuf = malloc_nf(VBUF_SIZE * sizeof *vbuf);
num_mobj = NUM_OBJ;
- mobj = malloc(num_mobj * sizeof *mobj);
- mobj[0] = metaobj_sgi();
- mobj[1] = metaobj_sflake();
+ mobjects = malloc(num_mobj * sizeof *mobj);
+ mobjects[0] = metaobj_sgi();
+ mobjects[1] = metaobj_sflake();
cur_obj = 1;
+ mobj = mobjects[cur_obj];
return 0;
}
cgm_vec3 pos;
float *vox = msurf_voxels(msurf);
- mobj[cur_obj]->update(mobj[cur_obj], tsec);
+ mobjects[cur_obj]->update(mobjects[cur_obj], tsec);
for(i=0; i<VOX_ZRES; i++) {
pos.z = -BBOX_HZSZ + i * VOX_ZSTEP;
/*energy += 5.0 / (pos.x + BBOX_HXSZ);
energy += 5.0 / (BBOX_HXSZ - pos.x);*/
- energy += mobj[cur_obj]->eval(mobj[cur_obj], &pos);
+ energy += mobj->eval(mobj, &pos);
*vox++ = energy;
}
void game_draw(void)
{
- unsigned long msec = game_getmsec();
- float tsec = (float)msec / 1000.0f;
+ float tsec;
+
+ time_msec = game_getmsec();
+ tsec = (float)time_msec / 1000.0f;
update(tsec);
int i, nverts, vbuf_count;
float *varr, *narr;
struct g3d_vertex *vbptr;
- static int nfrm;
nverts = msurf_vertex_count(msurf);
varr = msurf_vertices(msurf);
if(vbptr > vbuf) {
g3d_draw(G3D_TRIANGLES, vbuf, vbptr - vbuf);
}
-
- nfrm++;
}
void game_keyboard(int key, int press)
mousey = y;
if(bn == 0) {
- if(press && !grabbed) {
- grabbed = 1;
- } else if(!press && grabbed) {
- grabbed = 0;
+ if(press) {
+ if(y > 3 * FB_HEIGHT / 4) {
+ mobj->swstate(mobj, MOBJ_GRABING);
+ }
+ } else {
+ mobj->swstate(mobj, MOBJ_DROPPING);
}
}
}
if((dx | dy) == 0) return;
if(mousebn[0]) {
- if(grabbed) {
- mobj[cur_obj]->pos.x += dx * 0.1;
- mobj[cur_obj]->pos.y -= dy * 0.1;
- }
+ mobj->pos.x += dx * 0.1;
+ mobj->pos.y -= dy * 0.1;
}
if(mousebn[2]) {
cam_theta += (float)dx * (0.6f * 1.333333333f);
#include <stdio.h>
#include <string.h>
#include "cgmath/cgmath.h"
+#include "game.h"
#include "metasurf.h"
#include "metaobj.h"
#include "util.h"
-static void upd_sflake(struct mobject *mobj, float t);
-static float eval_sflake(struct mobject *mobj, cgm_vec3 *pos);
-static int num_balls(int depth);
+static struct mobject *mobj_create(int num);
+static void swstate(struct mobject *mobj, int st);
+static void update(struct mobject *mobj, float tsec);
+static float eval(struct mobject *mobj, cgm_vec3 *pos);
+
+static void upd_sflake_ball(struct mobject *mobj, struct mball *ball, float tsec, float t);
+static int calc_num_balls(int depth);
static int gen_sflake(cgm_vec4 *sarr, int num, int depth, float x, float y, float z, float rad);
-static void upd_sgi(struct mobject *mobj, float t);
-static float eval_sgi(struct mobject *mobj, cgm_vec3 *pos);
+static void upd_sgi_caps(struct mobject *mobj, struct mcapsule *caps, float tsec, float t);
+
static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos);
+static float easein(float x);
+static float easeout(float x);
-/* ---- sphereflake ---- */
-#define SF_MAX_DEPTH 2
-static cgm_vec4 *sfsph;
-struct mobject *metaobj_sflake(void)
+static struct mobject *mobj_create(int num)
{
+ int i;
struct mobject *mobj;
mobj = calloc_nf(1, sizeof *mobj);
- mobj->num_balls = num_balls(SF_MAX_DEPTH);
- mobj->balls = malloc_nf(mobj->num_balls * sizeof *mobj->balls);
- sfsph = malloc_nf(mobj->num_balls * sizeof *sfsph);
+ mobj->idlepos = malloc_nf(num * sizeof *mobj->idlepos);
+ mobj->mot = malloc_nf(num * sizeof *mobj->mot);
- gen_sflake(sfsph, 0, SF_MAX_DEPTH, 0, 0, 0, 20);
+ for(i=0; i<num; i++) {
+ mobj->mot[i].x = 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f;
+ mobj->mot[i].y = 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f;
+ mobj->mot[i].z = 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f;
+ mobj->mot[i].w = 0.8;
+ }
- mobj->update = upd_sflake;
- mobj->eval = eval_sflake;
+ mobj->swstate = swstate;
+ mobj->update = update;
+ mobj->eval = eval;
+
+ mobj->state = -1;
+ swstate(mobj, MOBJ_IDLE);
return mobj;
}
-static void upd_sflake(struct mobject *mobj, float t)
+static void swstate(struct mobject *mobj, int st)
{
- int i;
- struct mball *ball = mobj->balls;
- float mat[16];
+ if(st == mobj->state) return;
+ if(st == MOBJ_GRABING && mobj->state != MOBJ_IDLE) return;
+ if(st == MOBJ_DROPPING && mobj->state != MOBJ_HELD && mobj->state != MOBJ_GRABING) {
+ return;
+ }
- cgm_midentity(mat);
- cgm_mrotate_x(mat, t);
- cgm_mrotate_y(mat, t);
- cgm_mtranslate(mat, mobj->pos.x, mobj->pos.y, mobj->pos.z);
+ switch(st) {
+ case MOBJ_GRABING:
+ if(mobj->state != MOBJ_IDLE) return;
+ break;
+
+ case MOBJ_DROPPING:
+ if(mobj->state != MOBJ_HELD && mobj->state != MOBJ_GRABING) {
+ return;
+ }
+ break;
+
+ case MOBJ_IDLE:
+ mobj->pos.x = mobj->pos.z = 0.0f;
+ mobj->pos.y = -BBOX_YSZ * 0.5f;
+ break;
+ }
- for(i=0; i<mobj->num_balls; i++) {
- cgm_vcons(&ball->pos, sfsph[i].x, sfsph[i].y, sfsph[i].z);
- cgm_vmul_m4v3(&ball->pos, mat);
- ball->energy = sfsph[i].w;
- ball++;
+ mobj->state = st;
+ mobj->tstart = (float)time_msec / 1000.0f;
+}
+
+static void update(struct mobject *mobj, float tsec)
+{
+ int i, count;
+ struct mball *ball;
+ struct mcapsule *caps;
+ float t;
+ cgm_vec3 *idleptr;
+ cgm_vec4 *motptr;
+
+ count = mobj->num_balls + mobj->num_caps;
+
+ if(mobj->state != MOBJ_IDLE) {
+ cgm_midentity(mobj->xform);
+ cgm_mrotate_x(mobj->xform, tsec);
+ cgm_mrotate_y(mobj->xform, tsec);
+ cgm_mtranslate(mobj->xform, mobj->pos.x, mobj->pos.y, mobj->pos.z);
+ }
+ if(mobj->state != MOBJ_HELD) {
+ for(i=0; i<count; i++) {
+ mobj->idlepos[i].x = sin(tsec * mobj->mot[i].x + mobj->mot[i].y) * mobj->mot[i].z * 3.0f;
+ mobj->idlepos[i].z = cos(tsec * mobj->mot[i].z + mobj->mot[i].y) * mobj->mot[i].x * 3.0f;
+ mobj->idlepos[i].y = -BBOX_YSZ * 0.45f;
+ }
+ }
+
+ idleptr = mobj->idlepos;
+ motptr = mobj->mot;
+ ball = mobj->balls;
+ caps = mobj->caps;
+
+ switch(mobj->state) {
+ case MOBJ_IDLE:
+ if(mobj->balls) {
+ for(i=0; i<mobj->num_balls; i++) {
+ ball->pos = idleptr[i];
+ ball->energy = motptr[i].w;
+ ball++;
+ }
+ idleptr += mobj->num_balls;
+ motptr += mobj->num_balls;
+ }
+ if(mobj->caps) {
+ for(i=0; i<mobj->num_caps; i++) {
+ caps->end[0] = caps->end[1] = idleptr[i];
+ caps->energy = motptr[i].w;
+ caps++;
+ }
+ }
+ break;
+
+ case MOBJ_GRABING:
+ t = easeout((tsec - mobj->tstart) / TRANSDUR);
+ if(t >= 1.0f) mobj->swstate(mobj, MOBJ_HELD);
+ if(0) {
+ case MOBJ_DROPPING:
+ t = easein((tsec - mobj->tstart) / TRANSDUR);
+ if(t >= 1.0f) mobj->swstate(mobj, MOBJ_IDLE);
+ }
+ for(i=0; i<mobj->num_balls; i++) {
+ mobj->upd_ball(mobj, ball++, tsec, t);
+ }
+ for(i=0; i<mobj->num_caps; i++) {
+ mobj->upd_caps(mobj, caps++, tsec, t);
+ }
+ break;
+
+ case MOBJ_HELD:
+ for(i=0; i<mobj->num_balls; i++) {
+ mobj->upd_ball(mobj, ball++, tsec, 0);
+ }
+ for(i=0; i<mobj->num_caps; i++) {
+ mobj->upd_caps(mobj, caps++, tsec, 0);
+ }
+ break;
}
}
-static float eval_sflake(struct mobject *mobj, cgm_vec3 *pos)
+static float eval(struct mobject *mobj, cgm_vec3 *pos)
{
int i;
float dsq, energy = 0.0f;
struct mball *ball = mobj->balls;
+ struct mcapsule *caps = mobj->caps;
for(i=0; i<mobj->num_balls; i++) {
dsq = cgm_vdist_sq(&ball->pos, pos);
energy += ball->energy / dsq;
ball++;
}
+
+ for(i=0; i<mobj->num_caps; i++) {
+ dsq = capsule_distsq(mobj->caps + i, pos);
+ energy += caps->energy / dsq;
+ }
return energy;
}
-static int num_balls(int depth)
+
+/* ---- sphereflake ---- */
+#define SF_MAX_DEPTH 2
+static cgm_vec4 *sfsph;
+
+struct mobject *metaobj_sflake(void)
+{
+ int num_balls;
+ struct mobject *mobj;
+
+ num_balls = calc_num_balls(SF_MAX_DEPTH);
+
+ mobj = mobj_create(num_balls);
+
+ mobj->num_balls = num_balls;
+ mobj->balls = malloc_nf(num_balls * sizeof *mobj->balls);
+ sfsph = malloc_nf(num_balls * sizeof *sfsph);
+
+ gen_sflake(sfsph, 0, SF_MAX_DEPTH, 0, 0, 0, 20);
+
+ mobj->upd_ball = upd_sflake_ball;
+ return mobj;
+}
+
+static void upd_sflake_ball(struct mobject *mobj, struct mball *ball, float tsec, float t)
+{
+ int idx = ball - mobj->balls;
+ cgm_vec3 pos;
+
+ switch(mobj->state) {
+ case MOBJ_DROPPING:
+ t = 1.0f - t;
+ case MOBJ_GRABING:
+ cgm_vcons(&pos, sfsph[idx].x, sfsph[idx].y, sfsph[idx].z);
+ cgm_vmul_m4v3(&pos, mobj->xform);
+ cgm_vlerp(&ball->pos, mobj->idlepos + idx, &pos, t);
+ ball->energy = cgm_lerp(mobj->mot[idx].w, sfsph[idx].w, t);
+ break;
+
+ case MOBJ_HELD:
+ cgm_vcons(&ball->pos, sfsph[idx].x, sfsph[idx].y, sfsph[idx].z);
+ cgm_vmul_m4v3(&ball->pos, mobj->xform);
+ ball->energy = sfsph[idx].w;
+ break;
+ }
+}
+
+static int calc_num_balls(int depth)
{
if(!depth) return 0;
- return num_balls(depth - 1) * 6 + 1;
+ return calc_num_balls(depth - 1) * 6 + 1;
}
static int gen_sflake(cgm_vec4 *sarr, int num, int depth, float x, float y, float z, float rad)
int i;
struct mobject *mobj;
- mobj = calloc_nf(1, sizeof *mobj);
-
cgm_midentity(sgimat);
cgm_mrotate_y(sgimat, -M_PI / 4.0f);
cgm_mrotate_x(sgimat, M_PI / 4.0f);
cgm_mtranslate(sgimat, 0, -4, 0);
+ mobj = mobj_create(NUM_SGI_VERTS);
+
mobj->num_caps = NUM_SGI_VERTS;
mobj->caps = calloc_nf(mobj->num_caps, sizeof *mobj->caps);
mobj->caps[i].energy = 0.7;
}
- mobj->update = upd_sgi;
- mobj->eval = eval_sgi;
+ mobj->swstate = swstate;
return mobj;
}
-static void upd_sgi(struct mobject *mobj, float t)
+static void upd_sgi_caps(struct mobject *mobj, struct mcapsule *caps, float tsec, float t)
{
int i;
float mat[16];
}
}
-static float eval_sgi(struct mobject *mobj, cgm_vec3 *pos)
-{
- int i;
- float dsq, val = 0.0f;
-
- for(i=0; i<mobj->num_caps; i++) {
- dsq = capsule_distsq(mobj->caps + i, pos);
- val += mobj->caps[i].energy / dsq;
- }
-
- return val;
-}
-
static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos)
{
float t;
cgm_vadd_scaled(&pp, &dir, t);
return cgm_vdist_sq(&pp, pos);
}
+
+static float easein(float x)
+{
+ return x * x * x;
+}
+
+static float easeout(float x)
+{
+ return 1.0f - pow(1.0f - x, 3.0f);
+}