b6ae0c8f9c5043205fc5d33390f3572522be0e2b
[vrfileman] / src / meshgen.cc
1 #include <stdio.h>
2 #include "meshgen.h"
3 #include "mesh.h"
4
5 // -------- sphere --------
6
7 #define SURAD(u)        ((u) * 2.0 * M_PI)
8 #define SVRAD(v)        ((v) * M_PI)
9
10 static Vec3 sphvec(float theta, float phi)
11 {
12         return Vec3(sin(theta) * sin(phi),
13                         cos(phi),
14                         cos(theta) * sin(phi));
15 }
16
17 void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange)
18 {
19         if(urange == 0.0 || vrange == 0.0) return;
20
21         if(usub < 4) usub = 4;
22         if(vsub < 2) vsub = 2;
23
24         int uverts = usub + 1;
25         int vverts = vsub + 1;
26
27         int num_verts = uverts * vverts;
28         int num_quads = usub * vsub;
29         int num_tri = num_quads * 2;
30
31         mesh->clear();
32         Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
33         Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
34         Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
35         Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
36         unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
37
38         float du = urange / (float)(uverts - 1);
39         float dv = vrange / (float)(vverts - 1);
40
41         float u = 0.0;
42         for(int i=0; i<uverts; i++) {
43                 float theta = u * 2.0 * M_PI;
44
45                 float v = 0.0;
46                 for(int j=0; j<vverts; j++) {
47                         float phi = v * M_PI;
48
49                         Vec3 pos = sphvec(theta, phi);
50
51                         *varr++ = pos * rad;
52                         *narr++ = pos;
53                         *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f));
54                         *uvarr++ = Vec2(u / urange, v / vrange);
55
56                         if(i < usub && j < vsub) {
57                                 int idx = i * vverts + j;
58                                 *idxarr++ = idx;
59                                 *idxarr++ = idx + 1;
60                                 *idxarr++ = idx + vverts + 1;
61
62                                 *idxarr++ = idx;
63                                 *idxarr++ = idx + vverts + 1;
64                                 *idxarr++ = idx + vverts;
65                         }
66
67                         v += dv;
68                 }
69                 u += du;
70         }
71 }
72
73 // ------ geosphere ------
74 #define PHI             1.618034
75
76 static Vec3 icosa_pt[] = {
77         Vec3(PHI, 1, 0),
78         Vec3(-PHI, 1, 0),
79         Vec3(PHI, -1, 0),
80         Vec3(-PHI, -1, 0),
81         Vec3(1, 0, PHI),
82         Vec3(1, 0, -PHI),
83         Vec3(-1, 0, PHI),
84         Vec3(-1, 0, -PHI),
85         Vec3(0, PHI, 1),
86         Vec3(0, -PHI, 1),
87         Vec3(0, PHI, -1),
88         Vec3(0, -PHI, -1)
89 };
90 enum { P11, P12, P13, P14, P21, P22, P23, P24, P31, P32, P33, P34 };
91 static int icosa_idx[] = {
92         P11, P31, P21,
93         P11, P22, P33,
94         P13, P21, P32,
95         P13, P34, P22,
96         P12, P23, P31,
97         P12, P33, P24,
98         P14, P32, P23,
99         P14, P24, P34,
100
101         P11, P33, P31,
102         P12, P31, P33,
103         P13, P32, P34,
104         P14, P34, P32,
105
106         P21, P13, P11,
107         P22, P11, P13,
108         P23, P12, P14,
109         P24, P14, P12,
110
111         P31, P23, P21,
112         P32, P21, P23,
113         P33, P22, P24,
114         P34, P24, P22
115 };
116
117 static void geosphere(std::vector<Vec3> *verts, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, int iter)
118 {
119         if(!iter) {
120                 verts->push_back(v1);
121                 verts->push_back(v2);
122                 verts->push_back(v3);
123                 return;
124         }
125
126         Vec3 v12 = normalize(v1 + v2);
127         Vec3 v23 = normalize(v2 + v3);
128         Vec3 v31 = normalize(v3 + v1);
129
130         geosphere(verts, v1, v12, v31, iter - 1);
131         geosphere(verts, v2, v23, v12, iter - 1);
132         geosphere(verts, v3, v31, v23, iter - 1);
133         geosphere(verts, v12, v23, v31, iter - 1);
134 }
135
136 void gen_geosphere(Mesh *mesh, float rad, int subdiv, bool hemi)
137 {
138         int num_tri = (sizeof icosa_idx / sizeof *icosa_idx) / 3;
139
140         std::vector<Vec3> verts;
141         for(int i=0; i<num_tri; i++) {
142                 Vec3 v[3];
143
144                 for(int j=0; j<3; j++) {
145                         int vidx = icosa_idx[i * 3 + j];
146                         v[j] = normalize(icosa_pt[vidx]);
147                 }
148
149                 if(hemi && (v[0].y < 0.0 || v[1].y < 0.0 || v[2].y < 0.0)) {
150                         continue;
151                 }
152
153                 geosphere(&verts, v[0], v[1], v[2], subdiv);
154         }
155
156         int num_verts = (int)verts.size();
157
158         mesh->clear();
159         Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
160         Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
161         Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
162         Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
163
164         for(int i=0; i<num_verts; i++) {
165                 *varr++ = verts[i] * rad;
166                 *narr++ = verts[i];
167
168                 float theta = atan2(verts[i].z, verts[i].x);
169                 float phi = acos(verts[i].y);
170
171                 *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f));
172
173                 float u = 0.5 * theta / M_PI + 0.5;
174                 float v = phi / M_PI;
175                 *uvarr++ = Vec2(u, v);
176         }
177 }
178
179 // -------- torus -----------
180 static Vec3 torusvec(float theta, float phi, float mr, float rr)
181 {
182         theta = -theta;
183
184         float rx = -cos(phi) * rr + mr;
185         float ry = sin(phi) * rr;
186         float rz = 0.0;
187
188         float x = rx * sin(theta) + rz * cos(theta);
189         float y = ry;
190         float z = -rx * cos(theta) + rz * sin(theta);
191
192         return Vec3(x, y, z);
193 }
194
195 void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange, float vrange)
196 {
197         if(usub < 4) usub = 4;
198         if(vsub < 2) vsub = 2;
199
200         int uverts = usub + 1;
201         int vverts = vsub + 1;
202
203         int num_verts = uverts * vverts;
204         int num_quads = usub * vsub;
205         int num_tri = num_quads * 2;
206
207         mesh->clear();
208         Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
209         Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
210         Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
211         Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
212         unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
213
214         float du = urange / (float)(uverts - 1);
215         float dv = vrange / (float)(vverts - 1);
216
217         float u = 0.0;
218         for(int i=0; i<uverts; i++) {
219                 float theta = u * 2.0 * M_PI;
220
221                 float v = 0.0;
222                 for(int j=0; j<vverts; j++) {
223                         float phi = v * 2.0 * M_PI;
224
225                         Vec3 pos = torusvec(theta, phi, mainrad, ringrad);
226                         Vec3 cent = torusvec(theta, phi, mainrad, 0.0);
227
228                         *varr++ = pos;
229                         *narr++ = (pos - cent) / ringrad;
230
231                         Vec3 pprev = torusvec(theta - 0.1f, phi, mainrad, ringrad);
232                         Vec3 pnext = torusvec(theta + 0.1f, phi, mainrad, ringrad);
233
234                         *tarr++ = normalize(pnext - pprev);
235                         *uvarr++ = Vec2(u * urange, v * vrange);
236
237                         if(i < usub && j < vsub) {
238                                 int idx = i * vverts + j;
239                                 *idxarr++ = idx;
240                                 *idxarr++ = idx + 1;
241                                 *idxarr++ = idx + vverts + 1;
242
243                                 *idxarr++ = idx;
244                                 *idxarr++ = idx + vverts + 1;
245                                 *idxarr++ = idx + vverts;
246                         }
247
248                         v += dv;
249                 }
250                 u += du;
251         }
252 }
253
254
255 // -------- cylinder --------
256
257 static Vec3 cylvec(float theta, float height)
258 {
259         return Vec3(sin(theta), height, cos(theta));
260 }
261
262 void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
263 {
264         if(usub < 4) usub = 4;
265         if(vsub < 1) vsub = 1;
266
267         int uverts = usub + 1;
268         int vverts = vsub + 1;
269
270         int num_body_verts = uverts * vverts;
271         int num_body_quads = usub * vsub;
272         int num_body_tri = num_body_quads * 2;
273
274         int capvverts = capsub ? capsub + 1 : 0;
275         int num_cap_verts = uverts * capvverts;
276         int num_cap_quads = usub * capsub;
277         int num_cap_tri = num_cap_quads * 2;
278
279         int num_verts = num_body_verts + num_cap_verts * 2;
280         int num_tri = num_body_tri + num_cap_tri * 2;
281
282         mesh->clear();
283         Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
284         Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
285         Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
286         Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
287         unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
288
289         float du = urange / (float)(uverts - 1);
290         float dv = vrange / (float)(vverts - 1);
291
292         float u = 0.0;
293         for(int i=0; i<uverts; i++) {
294                 float theta = SURAD(u);
295
296                 float v = 0.0;
297                 for(int j=0; j<vverts; j++) {
298                         float y = (v - 0.5) * height;
299                         Vec3 pos = cylvec(theta, y);
300
301                         *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad);
302                         *narr++ = Vec3(pos.x, 0.0, pos.z);
303                         *tarr++ = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
304                         *uvarr++ = Vec2(u * urange, v * vrange);
305
306                         if(i < usub && j < vsub) {
307                                 int idx = i * vverts + j;
308
309                                 *idxarr++ = idx;
310                                 *idxarr++ = idx + vverts + 1;
311                                 *idxarr++ = idx + 1;
312
313                                 *idxarr++ = idx;
314                                 *idxarr++ = idx + vverts;
315                                 *idxarr++ = idx + vverts + 1;
316                         }
317
318                         v += dv;
319                 }
320                 u += du;
321         }
322
323
324         // now the cap!
325         if(!capsub) {
326                 return;
327         }
328
329         dv = 1.0 / (float)(capvverts - 1);
330
331         u = 0.0;
332         for(int i=0; i<uverts; i++) {
333                 float theta = SURAD(u);
334
335                 float v = 0.0;
336                 for(int j=0; j<capvverts; j++) {
337                         float r = v * rad;
338
339                         Vec3 pos = cylvec(theta, height / 2.0) * r;
340                         pos.y = height / 2.0;
341                         Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
342
343                         *varr++ = pos;
344                         *narr++ = Vec3(0, 1, 0);
345                         *tarr++ = tang;
346                         *uvarr++ = Vec2(u * urange, v);
347
348                         pos.y = -height / 2.0;
349                         *varr++ = pos;
350                         *narr++ = Vec3(0, -1, 0);
351                         *tarr++ = -tang;
352                         *uvarr++ = Vec2(u * urange, v);
353
354                         if(i < usub && j < capsub) {
355                                 unsigned int idx = num_body_verts + (i * capvverts + j) * 2;
356
357                                 unsigned int vidx[4] = {
358                                         idx,
359                                         idx + capvverts * 2,
360                                         idx + (capvverts + 1) * 2,
361                                         idx + 2
362                                 };
363
364                                 *idxarr++ = vidx[0];
365                                 *idxarr++ = vidx[2];
366                                 *idxarr++ = vidx[1];
367                                 *idxarr++ = vidx[0];
368                                 *idxarr++ = vidx[3];
369                                 *idxarr++ = vidx[2];
370
371                                 *idxarr++ = vidx[0] + 1;
372                                 *idxarr++ = vidx[1] + 1;
373                                 *idxarr++ = vidx[2] + 1;
374                                 *idxarr++ = vidx[0] + 1;
375                                 *idxarr++ = vidx[2] + 1;
376                                 *idxarr++ = vidx[3] + 1;
377                         }
378
379                         v += dv;
380                 }
381                 u += du;
382         }
383 }
384
385 // -------- cone --------
386
387 static Vec3 conevec(float theta, float y, float height)
388 {
389         float scale = 1.0 - y / height;
390         return Vec3(sin(theta) * scale, y, cos(theta) * scale);
391 }
392
393 void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
394 {
395         if(usub < 4) usub = 4;
396         if(vsub < 1) vsub = 1;
397
398         int uverts = usub + 1;
399         int vverts = vsub + 1;
400
401         int num_body_verts = uverts * vverts;
402         int num_body_quads = usub * vsub;
403         int num_body_tri = num_body_quads * 2;
404
405         int capvverts = capsub ? capsub + 1 : 0;
406         int num_cap_verts = uverts * capvverts;
407         int num_cap_quads = usub * capsub;
408         int num_cap_tri = num_cap_quads * 2;
409
410         int num_verts = num_body_verts + num_cap_verts;
411         int num_tri = num_body_tri + num_cap_tri;
412
413         mesh->clear();
414         Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
415         Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
416         Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
417         Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
418         unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
419
420         float du = urange / (float)(uverts - 1);
421         float dv = vrange / (float)(vverts - 1);
422
423         float u = 0.0;
424         for(int i=0; i<uverts; i++) {
425                 float theta = SURAD(u);
426
427                 float v = 0.0;
428                 for(int j=0; j<vverts; j++) {
429                         float y = v * height;
430                         Vec3 pos = conevec(theta, y, height);
431
432                         Vec3 tang = normalize(conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height));
433                         Vec3 bitang = normalize(conevec(theta, y + 0.1, height) - pos);
434
435                         *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad);
436                         *narr++ = cross(tang, bitang);
437                         *tarr++ = tang;
438                         *uvarr++ = Vec2(u * urange, v * vrange);
439
440                         if(i < usub && j < vsub) {
441                                 int idx = i * vverts + j;
442
443                                 *idxarr++ = idx;
444                                 *idxarr++ = idx + vverts + 1;
445                                 *idxarr++ = idx + 1;
446
447                                 *idxarr++ = idx;
448                                 *idxarr++ = idx + vverts;
449                                 *idxarr++ = idx + vverts + 1;
450                         }
451
452                         v += dv;
453                 }
454                 u += du;
455         }
456
457
458         // now the bottom cap!
459         if(!capsub) {
460                 return;
461         }
462
463         dv = 1.0 / (float)(capvverts - 1);
464
465         u = 0.0;
466         for(int i=0; i<uverts; i++) {
467                 float theta = SURAD(u);
468
469                 float v = 0.0;
470                 for(int j=0; j<capvverts; j++) {
471                         float r = v * rad;
472
473                         Vec3 pos = conevec(theta, 0.0, height) * r;
474                         Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
475
476                         *varr++ = pos;
477                         *narr++ = Vec3(0, -1, 0);
478                         *tarr++ = tang;
479                         *uvarr++ = Vec2(u * urange, v);
480
481                         if(i < usub && j < capsub) {
482                                 unsigned int idx = num_body_verts + i * capvverts + j;
483
484                                 unsigned int vidx[4] = {
485                                         idx,
486                                         idx + capvverts,
487                                         idx + (capvverts + 1),
488                                         idx + 1
489                                 };
490
491                                 *idxarr++ = vidx[0];
492                                 *idxarr++ = vidx[1];
493                                 *idxarr++ = vidx[2];
494                                 *idxarr++ = vidx[0];
495                                 *idxarr++ = vidx[2];
496                                 *idxarr++ = vidx[3];
497                         }
498
499                         v += dv;
500                 }
501                 u += du;
502         }
503 }
504
505
506 // -------- plane --------
507
508 void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub)
509 {
510         gen_heightmap(mesh, width, height, usub, vsub, 0);
511 }
512
513
514 // ----- heightmap ------
515
516 void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata)
517 {
518         if(usub < 1) usub = 1;
519         if(vsub < 1) vsub = 1;
520
521         mesh->clear();
522
523         int uverts = usub + 1;
524         int vverts = vsub + 1;
525         int num_verts = uverts * vverts;
526
527         int num_quads = usub * vsub;
528         int num_tri = num_quads * 2;
529
530         Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
531         Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
532         Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
533         Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
534         unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
535
536         float du = 1.0 / (float)usub;
537         float dv = 1.0 / (float)vsub;
538
539         float u = 0.0;
540         for(int i=0; i<uverts; i++) {
541                 float v = 0.0;
542                 for(int j=0; j<vverts; j++) {
543                         float x = (u - 0.5) * width;
544                         float y = (v - 0.5) * height;
545                         float z = hf ? hf(u, v, hfdata) : 0.0;
546
547                         Vec3 normal = Vec3(0, 0, 1);
548                         if(hf) {
549                                 float u1z = hf(u + du, v, hfdata);
550                                 float v1z = hf(u, v + dv, hfdata);
551
552                                 Vec3 tang = Vec3(du * width, 0, u1z - z);
553                                 Vec3 bitan = Vec3(0, dv * height, v1z - z);
554                                 normal = normalize(cross(tang, bitan));
555                         }
556
557                         *varr++ = Vec3(x, y, z);
558                         *narr++ = normal;
559                         *tarr++ = Vec3(1, 0, 0);
560                         *uvarr++ = Vec2(u, v);
561
562                         if(i < usub && j < vsub) {
563                                 int idx = i * vverts + j;
564
565                                 *idxarr++ = idx;
566                                 *idxarr++ = idx + vverts + 1;
567                                 *idxarr++ = idx + 1;
568
569                                 *idxarr++ = idx;
570                                 *idxarr++ = idx + vverts;
571                                 *idxarr++ = idx + vverts + 1;
572                         }
573
574                         v += dv;
575                 }
576                 u += du;
577         }
578 }
579
580 // ----- box ------
581 void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub, int vsub)
582 {
583         static const float face_angles[][2] = {
584                 {0, 0},
585                 {M_PI / 2.0, 0},
586                 {M_PI, 0},
587                 {3.0 * M_PI / 2.0, 0},
588                 {0, M_PI / 2.0},
589                 {0, -M_PI / 2.0}
590         };
591
592         if(usub < 1) usub = 1;
593         if(vsub < 1) vsub = 1;
594
595         mesh->clear();
596
597         for(int i=0; i<6; i++) {
598                 Mat4 xform, dir_xform;
599                 Mesh m;
600
601                 gen_plane(&m, 1, 1, usub, vsub);
602                 xform.rotate(Vec3(face_angles[i][1], face_angles[i][0], 0));
603                 dir_xform = xform;
604                 xform.translate(Vec3(0, 0, 0.5));
605                 m.apply_xform(xform, dir_xform);
606
607                 mesh->append(m);
608         }
609
610         Mat4 scale;
611         scale.scaling(xsz, ysz, zsz);
612         mesh->apply_xform(scale, Mat4::identity);
613 }
614
615 /*
616 void gen_box(Mesh *mesh, float xsz, float ysz, float zsz)
617 {
618         mesh->clear();
619
620         const int num_faces = 6;
621         int num_verts = num_faces * 4;
622         int num_tri = num_faces * 2;
623
624         float x = xsz / 2.0;
625         float y = ysz / 2.0;
626         float z = zsz / 2.0;
627
628         Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
629         Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
630         Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
631         Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
632         unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
633
634         static const Vec2 uv[] = { Vec2(0, 0), Vec2(1, 0), Vec2(1, 1), Vec2(0, 1) };
635
636         // front
637         for(int i=0; i<4; i++) {
638                 *narr++ = Vec3(0, 0, 1);
639                 *tarr++ = Vec3(1, 0, 0);
640                 *uvarr++ = uv[i];
641         }
642         *varr++ = Vec3(-x, -y, z);
643         *varr++ = Vec3(x, -y, z);
644         *varr++ = Vec3(x, y, z);
645         *varr++ = Vec3(-x, y, z);
646         // right
647         for(int i=0; i<4; i++) {
648                 *narr++ = Vec3(1, 0, 0);
649                 *tarr++ = Vec3(0, 0, -1);
650                 *uvarr++ = uv[i];
651         }
652         *varr++ = Vec3(x, -y, z);
653         *varr++ = Vec3(x, -y, -z);
654         *varr++ = Vec3(x, y, -z);
655         *varr++ = Vec3(x, y, z);
656         // back
657         for(int i=0; i<4; i++) {
658                 *narr++ = Vec3(0, 0, -1);
659                 *tarr++ = Vec3(-1, 0, 0);
660                 *uvarr++ = uv[i];
661         }
662         *varr++ = Vec3(x, -y, -z);
663         *varr++ = Vec3(-x, -y, -z);
664         *varr++ = Vec3(-x, y, -z);
665         *varr++ = Vec3(x, y, -z);
666         // left
667         for(int i=0; i<4; i++) {
668                 *narr++ = Vec3(-1, 0, 0);
669                 *tarr++ = Vec3(0, 0, 1);
670                 *uvarr++ = uv[i];
671         }
672         *varr++ = Vec3(-x, -y, -z);
673         *varr++ = Vec3(-x, -y, z);
674         *varr++ = Vec3(-x, y, z);
675         *varr++ = Vec3(-x, y, -z);
676         // top
677         for(int i=0; i<4; i++) {
678                 *narr++ = Vec3(0, 1, 0);
679                 *tarr++ = Vec3(1, 0, 0);
680                 *uvarr++ = uv[i];
681         }
682         *varr++ = Vec3(-x, y, z);
683         *varr++ = Vec3(x, y, z);
684         *varr++ = Vec3(x, y, -z);
685         *varr++ = Vec3(-x, y, -z);
686         // bottom
687         for(int i=0; i<4; i++) {
688                 *narr++ = Vec3(0, -1, 0);
689                 *tarr++ = Vec3(1, 0, 0);
690                 *uvarr++ = uv[i];
691         }
692         *varr++ = Vec3(-x, -y, -z);
693         *varr++ = Vec3(x, -y, -z);
694         *varr++ = Vec3(x, -y, z);
695         *varr++ = Vec3(-x, -y, z);
696
697         // index array
698         static const int faceidx[] = {0, 1, 2, 0, 2, 3};
699         for(int i=0; i<num_faces; i++) {
700                 for(int j=0; j<6; j++) {
701                         *idxarr++ = faceidx[j] + i * 4;
702                 }
703         }
704 }
705 */
706
707 static inline Vec3 rev_vert(float u, float v, Vec2 (*rf)(float, float, void*), void *cls)
708 {
709         Vec2 pos = rf(u, v, cls);
710
711         float angle = u * 2.0 * M_PI;
712         float x = pos.x * cos(angle);
713         float y = pos.y;
714         float z = pos.x * sin(angle);
715
716         return Vec3(x, y, z);
717 }
718
719 // ------ surface of revolution -------
720 void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*), void *cls)
721 {
722         gen_revol(mesh, usub, vsub, rfunc, 0, cls);
723 }
724
725 void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*),
726                 Vec2 (*nfunc)(float, float, void*), void *cls)
727 {
728         if(!rfunc) return;
729         if(usub < 3) usub = 3;
730         if(vsub < 1) vsub = 1;
731
732         mesh->clear();
733
734         int uverts = usub + 1;
735         int vverts = vsub + 1;
736         int num_verts = uverts * vverts;
737
738         int num_quads = usub * vsub;
739         int num_tri = num_quads * 2;
740
741         Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
742         Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
743         Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
744         Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
745         unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
746
747         float du = 1.0 / (float)(uverts - 1);
748         float dv = 1.0 / (float)(vverts - 1);
749
750         float u = 0.0;
751         for(int i=0; i<uverts; i++) {
752                 float v = 0.0;
753                 for(int j=0; j<vverts; j++) {
754                         Vec3 pos = rev_vert(u, v, rfunc, cls);
755
756                         Vec3 nextu = rev_vert(fmod(u + du, 1.0), v, rfunc, cls);
757                         Vec3 tang = nextu - pos;
758                         if(length_sq(tang) < 1e-6) {
759                                 float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
760                                 nextu = rev_vert(fmod(u + du, 1.0), new_v, rfunc, cls);
761                                 tang = nextu - pos;
762                         }
763
764                         Vec3 normal;
765                         if(nfunc) {
766                                 normal = rev_vert(u, v, nfunc, cls);
767                         } else {
768                                 Vec3 nextv = rev_vert(u, v + dv, rfunc, cls);
769                                 Vec3 bitan = nextv - pos;
770                                 if(length_sq(bitan) < 1e-6) {
771                                         nextv = rev_vert(u, v - dv, rfunc, cls);
772                                         bitan = pos - nextv;
773                                 }
774
775                                 normal = cross(tang, bitan);
776                         }
777
778                         *varr++ = pos;
779                         *narr++ = normalize(normal);
780                         *tarr++ = normalize(tang);
781                         *uvarr++ = Vec2(u, v);
782
783                         if(i < usub && j < vsub) {
784                                 int idx = i * vverts + j;
785
786                                 *idxarr++ = idx;
787                                 *idxarr++ = idx + vverts + 1;
788                                 *idxarr++ = idx + 1;
789
790                                 *idxarr++ = idx;
791                                 *idxarr++ = idx + vverts;
792                                 *idxarr++ = idx + vverts + 1;
793                         }
794
795                         v += dv;
796                 }
797                 u += du;
798         }
799 }
800
801
802 static inline Vec3 sweep_vert(float u, float v, float height, Vec2 (*sf)(float, float, void*), void *cls)
803 {
804         Vec2 pos = sf(u, v, cls);
805
806         float x = pos.x;
807         float y = v * height;
808         float z = pos.y;
809
810         return Vec3(x, y, z);
811 }
812
813 // ---- sweep shape along a path ----
814 void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vec2 (*sfunc)(float, float, void*), void *cls)
815 {
816         if(!sfunc) return;
817         if(usub < 3) usub = 3;
818         if(vsub < 1) vsub = 1;
819
820         mesh->clear();
821
822         int uverts = usub + 1;
823         int vverts = vsub + 1;
824         int num_verts = uverts * vverts;
825
826         int num_quads = usub * vsub;
827         int num_tri = num_quads * 2;
828
829         Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
830         Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
831         Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
832         Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
833         unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
834
835         float du = 1.0 / (float)(uverts - 1);
836         float dv = 1.0 / (float)(vverts - 1);
837
838         float u = 0.0;
839         for(int i=0; i<uverts; i++) {
840                 float v = 0.0;
841                 for(int j=0; j<vverts; j++) {
842                         Vec3 pos = sweep_vert(u, v, height, sfunc, cls);
843
844                         Vec3 nextu = sweep_vert(fmod(u + du, 1.0), v, height, sfunc, cls);
845                         Vec3 tang = nextu - pos;
846                         if(length_sq(tang) < 1e-6) {
847                                 float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
848                                 nextu = sweep_vert(fmod(u + du, 1.0), new_v, height, sfunc, cls);
849                                 tang = nextu - pos;
850                         }
851
852                         Vec3 normal;
853                         Vec3 nextv = sweep_vert(u, v + dv, height, sfunc, cls);
854                         Vec3 bitan = nextv - pos;
855                         if(length_sq(bitan) < 1e-6) {
856                                 nextv = sweep_vert(u, v - dv, height, sfunc, cls);
857                                 bitan = pos - nextv;
858                         }
859
860                         normal = cross(tang, bitan);
861
862                         *varr++ = pos;
863                         *narr++ = normalize(normal);
864                         *tarr++ = normalize(tang);
865                         *uvarr++ = Vec2(u, v);
866
867                         if(i < usub && j < vsub) {
868                                 int idx = i * vverts + j;
869
870                                 *idxarr++ = idx;
871                                 *idxarr++ = idx + vverts + 1;
872                                 *idxarr++ = idx + 1;
873
874                                 *idxarr++ = idx;
875                                 *idxarr++ = idx + vverts;
876                                 *idxarr++ = idx + vverts + 1;
877                         }
878
879                         v += dv;
880                 }
881                 u += du;
882         }
883 }