grab and drop, also refactor of metaobject callbacks
authorJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 12 Oct 2023 14:50:01 +0000 (17:50 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 12 Oct 2023 14:50:01 +0000 (17:50 +0300)
src/game.c
src/game.h
src/metaobj.c
src/metaobj.h

index 3d96161..88d8d1a 100644 (file)
 #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;
@@ -84,10 +81,11 @@ int game_init(void)
        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;
 }
 
@@ -102,7 +100,7 @@ static void update(float tsec)
        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;
@@ -116,7 +114,7 @@ static void update(float tsec)
                                /*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;
                        }
@@ -128,8 +126,10 @@ static void update(float tsec)
 
 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);
 
@@ -157,7 +157,6 @@ static void draw_metaballs(void)
        int i, nverts, vbuf_count;
        float *varr, *narr;
        struct g3d_vertex *vbptr;
-       static int nfrm;
 
        nverts = msurf_vertex_count(msurf);
        varr = msurf_vertices(msurf);
@@ -187,8 +186,6 @@ static void draw_metaballs(void)
        if(vbptr > vbuf) {
                g3d_draw(G3D_TRIANGLES, vbuf, vbptr - vbuf);
        }
-
-       nfrm++;
 }
 
 void game_keyboard(int key, int press)
@@ -203,10 +200,12 @@ void game_mouse(int bn, int press, int x, int y)
        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);
                }
        }
 }
@@ -221,10 +220,8 @@ void game_motion(int x, int y)
        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);
index c416037..037ff32 100644 (file)
@@ -4,7 +4,15 @@
 #define FB_WIDTH       320
 #define FB_HEIGHT      200
 
+#define BBOX_XSZ               16
+#define BBOX_YSZ               15
+#define BBOX_ZSZ               10
+#define VOX_RES                        24
+
+#define TRANSDUR               1.0f
+
 extern unsigned char *framebuf, *vmem;
+extern unsigned long time_msec;
 
 int game_init(void);
 void game_shutdown(void);
index 71790e5..aee79b4 100644 (file)
 #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)
@@ -130,13 +283,13 @@ struct mobject *metaobj_sgi(void)
        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);
 
@@ -144,12 +297,11 @@ struct mobject *metaobj_sgi(void)
                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];
@@ -172,19 +324,6 @@ static void upd_sgi(struct mobject *mobj, float t)
        }
 }
 
-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;
@@ -211,3 +350,13 @@ static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos)
        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);
+}
index cd73e8a..7dbee8a 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef METAOBJ_H_
 #define METAOBJ_H_
 
+enum {
+       MOBJ_IDLE,
+       MOBJ_GRABING,
+       MOBJ_HELD,
+       MOBJ_DROPPING
+};
 
 struct mball {
        float energy;
@@ -14,12 +20,20 @@ struct mcapsule {
 };
 
 struct mobject {
-       cgm_vec3 pos;
+       cgm_vec3 pos, mouse;
+       int state;
        struct mball *balls;
        struct mcapsule *caps;
        int num_balls, num_caps;
+       cgm_vec3 *idlepos;
+       cgm_vec4 *mot;
+       float tstart;
+       float xform[16];
 
-       void (*update)(struct mobject *mobj, float t);
+       void (*swstate)(struct mobject *mobj, int newst);
+       void (*update)(struct mobject *mobj, float tsec);
+       void (*upd_ball)(struct mobject *mobj, struct mball *ball, float tsec, float t);
+       void (*upd_caps)(struct mobject *mobj, struct mcapsule *caps, float tsec, float t);
        float (*eval)(struct mobject *mobj, cgm_vec3 *pos);
 };