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