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