meta shapes
[metatoy] / src / metaobj.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "cgmath/cgmath.h"
4 #include "metasurf.h"
5 #include "metaobj.h"
6 #include "util.h"
7
8 static void upd_sflake(struct mobject *mobj, float t);
9 static float eval_sflake(struct mobject *mobj, cgm_vec3 *pos);
10 static int num_balls(int depth);
11 static int gen_sflake(cgm_vec4 *sarr, int num, int depth, float x, float y, float z, float rad);
12
13 static void upd_sgi(struct mobject *mobj, float t);
14 static float eval_sgi(struct mobject *mobj, cgm_vec3 *pos);
15 static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos);
16
17 /* ---- sphereflake ---- */
18 #define SF_MAX_DEPTH    2
19 static cgm_vec4 *sfsph;
20
21 struct mobject *metaobj_sflake(void)
22 {
23         struct mobject *mobj;
24
25         mobj = calloc_nf(1, sizeof *mobj);
26
27         mobj->num_balls = num_balls(SF_MAX_DEPTH);
28         mobj->balls = malloc_nf(mobj->num_balls * sizeof *mobj->balls);
29         sfsph = malloc_nf(mobj->num_balls * sizeof *sfsph);
30
31         gen_sflake(sfsph, 0, SF_MAX_DEPTH, 0, 0, 0, 20);
32
33         mobj->update = upd_sflake;
34         mobj->eval = eval_sflake;
35         return mobj;
36 }
37
38 static void upd_sflake(struct mobject *mobj, float t)
39 {
40         int i;
41         struct mball *ball = mobj->balls;
42         float mat[16];
43
44         cgm_midentity(mat);
45         cgm_mrotate_x(mat, t);
46         cgm_mrotate_y(mat, t);
47         cgm_mtranslate(mat, mobj->pos.x, mobj->pos.y, mobj->pos.z);
48
49         for(i=0; i<mobj->num_balls; i++) {
50                 cgm_vcons(&ball->pos, sfsph[i].x, sfsph[i].y, sfsph[i].z);
51                 cgm_vmul_m4v3(&ball->pos, mat);
52                 ball->energy = sfsph[i].w;
53                 ball++;
54         }
55 }
56
57 static float eval_sflake(struct mobject *mobj, cgm_vec3 *pos)
58 {
59         int i;
60         float dsq, energy = 0.0f;
61         struct mball *ball = mobj->balls;
62
63         for(i=0; i<mobj->num_balls; i++) {
64                 dsq = cgm_vdist_sq(&ball->pos, pos);
65                 energy += ball->energy / dsq;
66                 ball++;
67         }
68         return energy;
69 }
70
71 static int num_balls(int depth)
72 {
73         if(!depth) return 0;
74         return num_balls(depth - 1) * 6 + 1;
75 }
76
77 static int gen_sflake(cgm_vec4 *sarr, int num, int depth, float x, float y, float z, float rad)
78 {
79         int subnum;
80         float subrad, offs;
81
82         if(!depth) return 0;
83
84         sarr[num].x = x;
85         sarr[num].y = y;
86         sarr[num].z = z;
87         sarr[num].w = rad;
88         num++;
89
90         subrad = rad * 0.2f;
91         offs = rad * 0.16f;
92
93         subnum = 0;
94         subnum += gen_sflake(sarr, num + subnum, depth - 1, x + offs, y, z, subrad);
95         subnum += gen_sflake(sarr, num + subnum, depth - 1, x - offs, y, z, subrad);
96         subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y + offs, z, subrad);
97         subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y - offs, z, subrad);
98         subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y, z + offs, subrad);
99         subnum += gen_sflake(sarr, num + subnum, depth - 1, x, y, z - offs, subrad);
100         return subnum + 1;
101 }
102
103 /* ---- SGI logo ---- */
104
105 static const cgm_vec3 sgiv[] = {
106         {2.794170, 4.254175, 2.738066},
107         {2.794170, 4.254174, -4.358471},
108         {-2.173414, 4.254174, -4.358471},
109         {-2.173414, -2.842363, -4.358470},
110         {4.923134, -2.842363, -4.358471},
111         {4.923134, 2.125212, -4.358471},
112         {4.923134, 2.125212, 2.738066},
113         {4.923134, -4.971326, 2.738067},
114         {4.923134, -4.971326, -2.229511},
115         {-2.173413, -4.971326, -2.229511},
116         {-2.173413, -4.971325, 4.867042},
117         {2.794170, -4.971325, 4.867042},
118         {2.794170, 2.125213, 4.867042},
119         {-4.302382, 2.125213, 4.867042},
120         {-4.302383, -2.842362, 4.867042},
121         {-4.302382, -2.842363, -2.229511},
122         {-4.302382, 4.254175, -2.229512},
123         {-4.302383, 4.254175, 2.738066}
124 };
125 #define NUM_SGI_VERTS   (sizeof sgiv / sizeof *sgiv)
126 static float sgimat[16];
127
128 struct mobject *metaobj_sgi(void)
129 {
130         int i;
131         struct mobject *mobj;
132
133         mobj = calloc_nf(1, sizeof *mobj);
134
135         cgm_midentity(sgimat);
136         cgm_mrotate_y(sgimat, -M_PI / 4.0f);
137         cgm_mrotate_x(sgimat, M_PI / 4.0f);
138         cgm_mtranslate(sgimat, 0, -4, 0);
139
140         mobj->num_caps = NUM_SGI_VERTS;
141         mobj->caps = calloc_nf(mobj->num_caps, sizeof *mobj->caps);
142
143         for(i=0; i<mobj->num_caps; i++) {
144                 mobj->caps[i].energy = 0.7;
145         }
146
147         mobj->update = upd_sgi;
148         mobj->eval = eval_sgi;
149         return mobj;
150 }
151
152 static void upd_sgi(struct mobject *mobj, float t)
153 {
154         int i;
155         float mat[16];
156         cgm_vec3 vpos[NUM_SGI_VERTS];
157
158         cgm_mcopy(mat, sgimat);
159         cgm_mrotate_y(mat, t);
160         cgm_mtranslate(mat, mobj->pos.x, mobj->pos.y, mobj->pos.z);
161
162         for(i=0; i<NUM_SGI_VERTS; i++) {
163                 vpos[i] = sgiv[i];
164                 cgm_vscale(vpos + i, 0.5);
165                 cgm_vmul_m4v3(vpos + i, mat);
166         }
167
168         for(i=0; i<NUM_SGI_VERTS; i++) {
169                 mobj->caps[i].end[0] = vpos[i];
170                 mobj->caps[i].end[1] = vpos[(i + 1) % NUM_SGI_VERTS];
171                 mobj->caps[i].len = cgm_vdist(mobj->caps[i].end, mobj->caps[i].end + 1);
172         }
173 }
174
175 static float eval_sgi(struct mobject *mobj, cgm_vec3 *pos)
176 {
177         int i;
178         float dsq, val = 0.0f;
179
180         for(i=0; i<mobj->num_caps; i++) {
181                 dsq = capsule_distsq(mobj->caps + i, pos);
182                 val += mobj->caps[i].energy / dsq;
183         }
184
185         return val;
186 }
187
188 static float capsule_distsq(struct mcapsule *c, cgm_vec3 *pos)
189 {
190         float t;
191         cgm_vec3 pp, dir, pdir;
192
193         dir = c->end[1]; cgm_vsub(&dir, c->end);
194         if(c->len != 0.0f) {
195                 float s = 1.0f / c->len;
196                 dir.x *= s;
197                 dir.y *= s;
198                 dir.z *= s;
199         }
200         pdir = *pos; cgm_vsub(&pdir, c->end);
201         t = cgm_vdot(&dir, &pdir);
202
203         if(t < 0.0f) {
204                 return cgm_vdist_sq(c->end, pos);
205         }
206         if(t > c->len) {
207                 return cgm_vdist_sq(c->end + 1, pos);
208         }
209
210         pp = c->end[0];
211         cgm_vadd_scaled(&pp, &dir, t);
212         return cgm_vdist_sq(&pp, pos);
213 }