meta shapes
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 11 Oct 2023 05:27:56 +0000 (08:27 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 11 Oct 2023 05:27:56 +0000 (08:27 +0300)
Makefile
src/game.c
src/metaobj.c [new file with mode: 0644]
src/metaobj.h [new file with mode: 0644]

index dfd0e35..e4b62f8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ bin = game
 
 inc = -Isrc -Isrc/3dgfx -Isrc/kern
 
-CFLAGS = -pedantic -Wall -g $(inc) -MMD
+CFLAGS = -pedantic -Wall -O2 -ffast-math -fno-strict-aliasing -g $(inc) -MMD
 LDFLAGS = -lGL -lX11 -lXext -lm
 
 $(bin): $(obj)
index 70f40c4..136fb4f 100644 (file)
@@ -8,12 +8,13 @@
 #include "metasurf.h"
 #include "util.h"
 #include "cgmath/cgmath.h"
+#include "metaobj.h"
 
 #define BBOX_SIZE              10.0f
 #define BBOX_HEIGHT            15.0f
 #define BBOX_HSZ               (BBOX_SIZE / 2.0f)
 #define BBOX_HH                        (BBOX_HEIGHT / 2.0f)
-#define VOX_RES                        30
+#define VOX_RES                        32
 #define VOX_YRES               (VOX_RES * BBOX_HEIGHT / BBOX_SIZE)
 #define VOX_STEP               (BBOX_SIZE / (float)VOX_RES)
 #define VOX_YSTEP              (BBOX_HEIGHT / (float)VOX_YRES)
 #define VBUF_MAX_TRIS  256
 #define VBUF_SIZE              (VBUF_MAX_TRIS * 3)
 
-struct mball {
-       float energy;
-       cgm_vec3 pos;
-};
-
-struct mcapsule {
-       float energy;
-       cgm_vec3 end[2];
-       float len;
-};
-
-static struct g3d_mesh mesh;
 static struct g3d_vertex *vbuf;
 static struct metasurface *msurf;
-static struct mball *balls;
-static int num_balls;
-static struct mcapsule *caps;
-static int num_caps;
+static struct mobject **mobj;
+
+#define NUM_OBJ                2
+static int num_mobj, cur_obj;
+static int grabbed;
+
+static int mousebn[3];
+static int mousex, mousey;
+static float cam_theta, cam_phi;
+
 
 static void update(float tsec);
 static void draw_metaballs(void);
-static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos);
-
-static cgm_vec3 sgiv[] = {
-       {2.794170, 4.254175, 2.738066},
-       {2.794170, 4.254174, -4.358471},
-       {-2.173414, 4.254174, -4.358471},
-       {-2.173414, -2.842363, -4.358470},
-       {4.923134, -2.842363, -4.358471},
-       {4.923134, 2.125212, -4.358471},
-       {4.923134, 2.125212, 2.738066},
-       {4.923134, -4.971326, 2.738067},
-       {4.923134, -4.971326, -2.229511},
-       {-2.173413, -4.971326, -2.229511},
-       {-2.173413, -4.971325, 4.867042},
-       {2.794170, -4.971325, 4.867042},
-       {2.794170, 2.125213, 4.867042},
-       {-4.302382, 2.125213, 4.867042},
-       {-4.302383, -2.842362, 4.867042},
-       {-4.302382, -2.842363, -2.229511},
-       {-4.302382, 4.254175, -2.229512},
-       {-4.302383, 4.254175, 2.738066}
-};
+
 
 int game_init(void)
 {
-       int i;
-       float mat[16];
-
        init_colormgr();
 
        g3d_init();
@@ -89,8 +60,6 @@ int game_init(void)
 
        g3d_polygon_mode(G3D_GOURAUD);
 
-       gen_torus_mesh(&mesh, 2.0, 0.7, 24, 12);
-
        if(!(msurf = msurf_create())) {
                return -1;
        }
@@ -102,30 +71,11 @@ int game_init(void)
 
        vbuf = malloc_nf(VBUF_SIZE * sizeof *vbuf);
 
-       num_balls = 0;
-       balls = calloc_nf(num_balls, sizeof *balls);
-       num_caps = sizeof sgiv / sizeof *sgiv;
-       caps = calloc_nf(num_caps, sizeof *caps);
-
-       for(i=0; i<num_balls; i++) {
-               balls[i].energy = 5;
-       }
-
-       cgm_midentity(mat);
-       cgm_mtranslate(mat, 0, -BBOX_HH / 2, 0);
-       cgm_mrotate_y(mat, -M_PI / 4.0f);
-       cgm_mrotate_x(mat, M_PI / 4.0f);
-
-       for(i=0; i<num_caps; i++) {
-               caps[i].energy = 1;
-               caps[i].end[0] = sgiv[i];
-               cgm_vscale(caps[i].end, 0.6);
-               caps[i].end[1] = sgiv[(i + 1) % num_caps];
-               cgm_vscale(caps[i].end + 1, 0.6);
-
-               cgm_vmul_m4v3(caps[i].end, mat);
-               cgm_vmul_m4v3(caps[i].end + 1, mat);
-       }
+       num_mobj = NUM_OBJ;
+       mobj = malloc(num_mobj * sizeof *mobj);
+       mobj[0] = metaobj_sgi();
+       mobj[1] = metaobj_sflake();
+       cur_obj = 1;
        return 0;
 }
 
@@ -135,21 +85,12 @@ void game_shutdown(void)
 
 static void update(float tsec)
 {
-       int i, j, k, n;
-       float dsq, energy;
+       int i, j, k;
+       float energy;
        cgm_vec3 pos;
        float *vox = msurf_voxels(msurf);
 
-       for(i=0; i<num_balls; i++) {
-               balls[i].pos.y = sin(tsec) * BBOX_HH;
-       }
-
-       float y = sin(tsec) * BBOX_HH / 80.0f;
-       for(i=0; i<num_caps; i++) {
-               caps[i].end[0].y += y;
-               caps[i].end[1].y += y;
-               caps[i].len = cgm_vdist(caps[i].end, caps[i].end + 1);
-       }
+       mobj[cur_obj]->update(mobj[cur_obj], tsec);
 
        for(i=0; i<VOX_RES; i++) {
                pos.z = -BBOX_HSZ + i * VOX_STEP;
@@ -161,17 +102,7 @@ static void update(float tsec)
                                /* initialize with the vertical distance for the pool */
                                energy = 5.0 / (pos.y + BBOX_HH * 0.98);
 
-                               /* add the contribution of the balls */
-                               for(n=0; n<num_balls; n++) {
-                                       dsq = cgm_vdist_sq(&balls[n].pos, &pos);
-                                       energy += balls[n].energy / dsq;
-                               }
-
-                               /* add the contribution of the capsules */
-                               for(n=0; n<num_caps; n++) {
-                                       dsq = capsule_distsq(caps + n, &pos);
-                                       energy += caps[n].energy / dsq;
-                               }
+                               energy += mobj[cur_obj]->eval(mobj[cur_obj], &pos);
 
                                *vox++ = energy;
                        }
@@ -193,6 +124,8 @@ void game_draw(void)
        g3d_matrix_mode(G3D_MODELVIEW);
        g3d_load_identity();
        g3d_translate(0, 1, -15);
+       g3d_rotate(cam_phi, 1, 0, 0);
+       g3d_rotate(cam_theta, 0, 1, 0);
        /*g3d_rotate(tsec * 50.0f, 1, 0, 0);
        g3d_rotate(tsec * 30.0f, 0, 0, 1);
 
@@ -248,35 +181,38 @@ void game_keyboard(int key, int press)
 
 void game_mouse(int bn, int press, int x, int y)
 {
+       mousebn[bn] = press;
+       mousex = x;
+       mousey = y;
+
+       if(bn == 0) {
+               if(press && !grabbed) {
+                       grabbed = 1;
+               } else if(!press && grabbed) {
+                       grabbed = 0;
+               }
+       }
 }
 
 void game_motion(int x, int y)
 {
-}
+       int dx = x - mousex;
+       int dy = y - mousey;
+       mousex = x;
+       mousey = y;
 
-static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos)
-{
-       float t;
-       cgm_vec3 pp, dir, pdir;
-
-       dir = c->end[1]; cgm_vsub(&dir, c->end);
-       if(c->len != 0.0f) {
-               float s = 1.0f / c->len;
-               dir.x *= s;
-               dir.y *= s;
-               dir.z *= s;
-       }
-       pdir = *pos; cgm_vsub(&pdir, c->end);
-       t = cgm_vdot(&dir, &pdir);
+       if((dx | dy) == 0) return;
 
-       if(t < 0.0f) {
-               return cgm_vdist_sq(c->end, pos);
+       if(mousebn[0]) {
+               if(grabbed) {
+                       mobj[cur_obj]->pos.x += dx * 0.1;
+                       mobj[cur_obj]->pos.y -= dy * 0.1;
+               }
        }
-       if(t > c->len) {
-               return cgm_vdist_sq(c->end + 1, pos);
+       if(mousebn[2]) {
+               cam_theta += (float)dx * (0.6f * 1.333333333f);
+               cam_phi += (float)dy * 0.6f;
+               if(cam_phi < -90) cam_phi = -90;
+               if(cam_phi > 90) cam_phi = 90;
        }
-
-       pp = c->end[0];
-       cgm_vadd_scaled(&pp, &dir, t);
-       return cgm_vdist_sq(&pp, pos);
 }
diff --git a/src/metaobj.c b/src/metaobj.c
new file mode 100644 (file)
index 0000000..71790e5
--- /dev/null
@@ -0,0 +1,213 @@
+#include <stdio.h>
+#include <string.h>
+#include "cgmath/cgmath.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 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 float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos);
+
+/* ---- sphereflake ---- */
+#define SF_MAX_DEPTH   2
+static cgm_vec4 *sfsph;
+
+struct mobject *metaobj_sflake(void)
+{
+       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);
+
+       gen_sflake(sfsph, 0, SF_MAX_DEPTH, 0, 0, 0, 20);
+
+       mobj->update = upd_sflake;
+       mobj->eval = eval_sflake;
+       return mobj;
+}
+
+static void upd_sflake(struct mobject *mobj, float t)
+{
+       int i;
+       struct mball *ball = mobj->balls;
+       float mat[16];
+
+       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);
+
+       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++;
+       }
+}
+
+static float eval_sflake(struct mobject *mobj, cgm_vec3 *pos)
+{
+       int i;
+       float dsq, energy = 0.0f;
+       struct mball *ball = mobj->balls;
+
+       for(i=0; i<mobj->num_balls; i++) {
+               dsq = cgm_vdist_sq(&ball->pos, pos);
+               energy += ball->energy / dsq;
+               ball++;
+       }
+       return energy;
+}
+
+static int num_balls(int depth)
+{
+       if(!depth) return 0;
+       return 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 subnum;
+       float subrad, offs;
+
+       if(!depth) return 0;
+
+       sarr[num].x = x;
+       sarr[num].y = y;
+       sarr[num].z = z;
+       sarr[num].w = rad;
+       num++;
+
+       subrad = rad * 0.2f;
+       offs = rad * 0.16f;
+
+       subnum = 0;
+       subnum += gen_sflake(sarr, num + subnum, depth - 1, x + offs, y, z, subrad);
+       subnum += gen_sflake(sarr, num + subnum, depth - 1, x - offs, y, z, subrad);
+       subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y + offs, z, subrad);
+       subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y - offs, z, subrad);
+       subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y, z + offs, subrad);
+       subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y, z - offs, subrad);
+       return subnum + 1;
+}
+
+/* ---- SGI logo ---- */
+
+static const cgm_vec3 sgiv[] = {
+       {2.794170, 4.254175, 2.738066},
+       {2.794170, 4.254174, -4.358471},
+       {-2.173414, 4.254174, -4.358471},
+       {-2.173414, -2.842363, -4.358470},
+       {4.923134, -2.842363, -4.358471},
+       {4.923134, 2.125212, -4.358471},
+       {4.923134, 2.125212, 2.738066},
+       {4.923134, -4.971326, 2.738067},
+       {4.923134, -4.971326, -2.229511},
+       {-2.173413, -4.971326, -2.229511},
+       {-2.173413, -4.971325, 4.867042},
+       {2.794170, -4.971325, 4.867042},
+       {2.794170, 2.125213, 4.867042},
+       {-4.302382, 2.125213, 4.867042},
+       {-4.302383, -2.842362, 4.867042},
+       {-4.302382, -2.842363, -2.229511},
+       {-4.302382, 4.254175, -2.229512},
+       {-4.302383, 4.254175, 2.738066}
+};
+#define NUM_SGI_VERTS  (sizeof sgiv / sizeof *sgiv)
+static float sgimat[16];
+
+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->num_caps = NUM_SGI_VERTS;
+       mobj->caps = calloc_nf(mobj->num_caps, sizeof *mobj->caps);
+
+       for(i=0; i<mobj->num_caps; i++) {
+               mobj->caps[i].energy = 0.7;
+       }
+
+       mobj->update = upd_sgi;
+       mobj->eval = eval_sgi;
+       return mobj;
+}
+
+static void upd_sgi(struct mobject *mobj, float t)
+{
+       int i;
+       float mat[16];
+       cgm_vec3 vpos[NUM_SGI_VERTS];
+
+       cgm_mcopy(mat, sgimat);
+       cgm_mrotate_y(mat, t);
+       cgm_mtranslate(mat, mobj->pos.x, mobj->pos.y, mobj->pos.z);
+
+       for(i=0; i<NUM_SGI_VERTS; i++) {
+               vpos[i] = sgiv[i];
+               cgm_vscale(vpos + i, 0.5);
+               cgm_vmul_m4v3(vpos + i, mat);
+       }
+
+       for(i=0; i<NUM_SGI_VERTS; i++) {
+               mobj->caps[i].end[0] = vpos[i];
+               mobj->caps[i].end[1] = vpos[(i + 1) % NUM_SGI_VERTS];
+               mobj->caps[i].len = cgm_vdist(mobj->caps[i].end, mobj->caps[i].end + 1);
+       }
+}
+
+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_vec3 pp, dir, pdir;
+
+       dir = c->end[1]; cgm_vsub(&dir, c->end);
+       if(c->len != 0.0f) {
+               float s = 1.0f / c->len;
+               dir.x *= s;
+               dir.y *= s;
+               dir.z *= s;
+       }
+       pdir = *pos; cgm_vsub(&pdir, c->end);
+       t = cgm_vdot(&dir, &pdir);
+
+       if(t < 0.0f) {
+               return cgm_vdist_sq(c->end, pos);
+       }
+       if(t > c->len) {
+               return cgm_vdist_sq(c->end + 1, pos);
+       }
+
+       pp = c->end[0];
+       cgm_vadd_scaled(&pp, &dir, t);
+       return cgm_vdist_sq(&pp, pos);
+}
diff --git a/src/metaobj.h b/src/metaobj.h
new file mode 100644 (file)
index 0000000..cd73e8a
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef METAOBJ_H_
+#define METAOBJ_H_
+
+
+struct mball {
+       float energy;
+       cgm_vec3 pos;
+};
+
+struct mcapsule {
+       float energy;
+       cgm_vec3 end[2];
+       float len;
+};
+
+struct mobject {
+       cgm_vec3 pos;
+       struct mball *balls;
+       struct mcapsule *caps;
+       int num_balls, num_caps;
+
+       void (*update)(struct mobject *mobj, float t);
+       float (*eval)(struct mobject *mobj, cgm_vec3 *pos);
+};
+
+struct mobject *metaobj_sflake(void);
+struct mobject *metaobj_sgi(void);
+
+#endif /* METAOBJ_H_ */